package com.joysuch.wwyt.workflow.service.impl;


import cn.hutool.json.JSONUtil;
import cn.zlg.common.enums.BusinessTypeEnum;
import cn.zlg.common.util.CollectionUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.joysuch.wwyt.alert.AlertListenerConfig;
import com.joysuch.wwyt.alert.service.NoticeWaitingTriggerListService;
import com.joysuch.wwyt.api.sync.service.HiddenDangerSender;
import com.joysuch.wwyt.bp.constant.AppNotifyContentPre;
import com.joysuch.wwyt.bp.entity.BpEnterpriseInfo;
import com.joysuch.wwyt.bp.entity.BpInspection;
import com.joysuch.wwyt.bp.entity.investigate.BpInvestigateRecord;
import com.joysuch.wwyt.bp.entity.investigate.BpInvestigateRecordItem;
import com.joysuch.wwyt.bp.entity.vo.BpInspectionVo;
import com.joysuch.wwyt.bp.mapper.BpInvestigateTaskHisMapper;
import com.joysuch.wwyt.bp.repository.*;
import com.joysuch.wwyt.bp.service.BpInvestigateRecordService;
import com.joysuch.wwyt.bp.service.impl.BpInspectionServiceImpl;
import com.joysuch.wwyt.common.constant.Constant;
import com.joysuch.wwyt.common.entity.CommonBusinessNotice;
import com.joysuch.wwyt.common.entity.CommonIndexNotify;
import com.joysuch.wwyt.common.enums.AppBusinessNoticeTypes;
import com.joysuch.wwyt.common.repository.CommonIndexNotifyDao;
import com.joysuch.wwyt.common.service.CommonBusinessNoticeService;
import com.joysuch.wwyt.config.RedisClient;
import com.joysuch.wwyt.core.common.ajax.ResultBean;
import com.joysuch.wwyt.core.common.util.DateTimeUtil;
import com.joysuch.wwyt.core.common.util.PageDataUtils;
import com.joysuch.wwyt.core.common.util.SimpleDateFormatCache;
import com.joysuch.wwyt.core.entity.BaseConfig;
import com.joysuch.wwyt.core.entity.BaseRole;
import com.joysuch.wwyt.core.enums.BaseConfigCodes;
import com.joysuch.wwyt.core.enums.Status;
import com.joysuch.wwyt.core.exception.ApiBusinessException;
import com.joysuch.wwyt.core.repository.BaseRoleUserLoginRoleDao;
import com.joysuch.wwyt.core.repository.BaseUserDao;
import com.joysuch.wwyt.core.security.ShiroUser;
import com.joysuch.wwyt.core.service.BaseConfigService;
import com.joysuch.wwyt.core.service.BaseRoleService;
import com.joysuch.wwyt.core.support.Context;
import com.joysuch.wwyt.mh.entity.MhMajorHazardTaskRecord;
import com.joysuch.wwyt.mh.entity.MhMajorHazardTaskRecordItem;
import com.joysuch.wwyt.mh.mapper.MhMajorHazardTaskRecordMapper;
import com.joysuch.wwyt.mh.service.MhMajorHazardTaskRecordItemService;
import com.joysuch.wwyt.mh.service.MhMajorHazardTaskRecordService;
import com.joysuch.wwyt.mh.service.MonitorPointDataWebSocketService;
import com.joysuch.wwyt.monitoringcenter.service.LocateServerService;
import com.joysuch.wwyt.patrol.entity.PatrolRecordItem;
import com.joysuch.wwyt.patrol.service.PatrolRecordItemService;
import com.joysuch.wwyt.risk.entity.RiskDistrict;
import com.joysuch.wwyt.risk.repository.RiskDistrictDao;
import com.joysuch.wwyt.risk.repository.RiskDynamicConfigDao;
import com.joysuch.wwyt.risk.repository.RiskEvaluationControlDao;
import com.joysuch.wwyt.risk.service.RiskDynamicRecordService;
import com.joysuch.wwyt.risk.service.RiskEvaluationBusinessService;
import com.joysuch.wwyt.risk.service.RiskEvaluationPlanService;
import com.joysuch.wwyt.workflow.WorkFlowConstants;
import com.joysuch.wwyt.workflow.api.service.WorkFlowAPIService;
import com.joysuch.wwyt.workflow.bean.*;
import com.joysuch.wwyt.workflow.bean.railAlarm.*;
import com.joysuch.wwyt.workflow.bean.vo.RelatedTaskInfoVO;
import com.joysuch.wwyt.workflow.engine.JumpTaskCommand;
import com.joysuch.wwyt.workflow.engine.ProcessAPI;
import com.joysuch.wwyt.workflow.entity.*;
import com.joysuch.wwyt.workflow.entity.bo.ComponentStatisticBO;
import com.joysuch.wwyt.workflow.entity.dto.WorkFlowAuthConfigDto;
import com.joysuch.wwyt.workflow.enums.*;
import com.joysuch.wwyt.workflow.repository.*;
import com.joysuch.wwyt.workflow.service.*;
import javafx.util.Pair;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.activiti.engine.ManagementService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.util.Assert;
import org.redisson.api.RList;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.EntityManager;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadLocalRandom;
import java.util.function.Function;
import java.util.stream.Collectors;

@Slf4j
@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class WorkFlowTaskServiceImpl implements WorkFlowTaskService {

    @Autowired
    private WorkFlowTaskDao workFlowTaskDao;
    @Autowired
    private RuntimeService runtimeService;
    @Autowired
    private TaskService taskService;
    @Autowired
    private WorkFlowProcessService workFlowProcessService;
    @Autowired
    private ManagementService managementService;
    @Autowired
    private EntityManager entityManager;
    @Autowired
    private WorkFlowTaskHistoryDao workFlowTaskHistoryDao;
    @Autowired
    private WorkFlowTaskAssignHistoryDao workFlowTaskAssignHistoryDao;
    @Autowired
    private HiddenDangerSender hiddenDangerSender;
    @Autowired
    private WorkFlowAPIService workFlowAPIService;
    @Autowired
    private BaseUserDao baseUserDao;
    @Autowired
    private BpDepartDao departDao;
    @Autowired
    private BpJobDao jobDao;
    @Autowired
    private BaseRoleService roleService;
    @Autowired
    private RiskEvaluationPlanService riskEvaluationPlanService;
    @Autowired
    private RiskDistrictDao riskDistrictDao;
    @Autowired
    private BaseRoleUserLoginRoleDao baseRoleUserLoginRoleDao;
    @Autowired
    private WorkFlowProcessDao processDao;
    @Autowired
    private WorkFlowLocationConfigDao locationConfigDao;
    @Autowired
    private WorkFlowRailAlarmConfigDao railAlarmConfigDao;
    @Autowired
    private WorkFlowRailAlarmTaskDao railAlarmTaskDao;
    @Autowired
    private LocateServerService locateServerService;
    @Autowired
    private BpContractorStaffDao contractorStaffDao;
    @Autowired
    private RiskEvaluationBusinessService riskEvaluationBusinessService;
    @Autowired
    private BpInvestigateRecordItemDao bpInvestigateRecordItemDao;
    @Autowired
    private WorkFlowProcessCodeStrategyDao workFlowProcessCodeStrategyDao;
    @Autowired
    private CommonIndexNotifyDao commonIndexNotifyDao;
    @Autowired
    private BaseConfigService baseConfigService;
    @Autowired
    private ProcessNoticeListService processNoticeListService;
    @Autowired
    private NoticeWaitingTriggerListService noticeWaitingTriggerListService;
    @Autowired
    private WorkFlowTaskProcessListService workFlowTaskProcessListService;
    @Autowired
    private BpInvestigateRecordService investigateRecordService;
    @Autowired
    private MonitorPointDataWebSocketService monitorPointDataWebSocketService;
    @Autowired
    private CommonBusinessNoticeService commonBusinessNoticeService;
    @Autowired
    private BpInvestigateRecordRepository investigateRecordRepository;
    @Autowired
    private PatrolRecordItemService patrolRecordItemService;
    @Autowired
    private RiskDynamicConfigDao riskDynamicConfigDao;
    @Autowired
    private RiskDynamicRecordService riskDynamicRecordService;
    @Autowired
    private RedisClient redisClient;
    @Autowired
    private WorkFlowTaskDynamicService workFlowTaskDynamicService;
    @Autowired
    private RiskEvaluationControlDao riskEvaluationControlDao;
    @Autowired
    private WorkFlowLocationConfigDao workFlowLocationConfigDao;
    @Autowired
    private BpInspectionServiceImpl bpInspectionService;
    @Autowired
    private BpInvestigateTaskHisMapper investigateHistoryMapper;
    @Autowired
    private MhMajorHazardTaskRecordItemService mhMajorHazardTaskRecordItemService;
    @Autowired
    private MhMajorHazardTaskRecordService mhMajorHazardTaskRecordService;
    @Autowired
    private MhMajorHazardTaskRecordMapper mhMajorHazardTaskRecordMapper;


    private final ProcessAPI processAPI;


    private String addStatus4FormData(String formData, String srcTaskName, String taskName, WorkFlowTask bizTask,
                                      List<WorkFlowTaskNameBean> taskNameList, String taskCode, String exceptionStatus) {

        String status = null;
        //节点的状态
        WorkFlowTaskNameBean taskNameBean = taskNameList.stream().filter(item -> item.getTaskName().equalsIgnoreCase(taskName)).collect(Collectors.toList()).get(0);
        //taskStatus为空的情况存在于: 有多个支流指向当前节点，这时取taskStatusMap, 以节点名称为key，支流上的名称为value
        //这就要求节点名称不能重复
        if (taskNameBean.getTaskStatus() == null) {
            status = taskNameBean.getTaskStatusMap().get(srcTaskName);
//            if(srcTaskName == null){
//                status = taskNameBean.getTaskStatusMap().get("1");
//            }else{
//                status = taskNameBean.getTaskStatusMap().get(srcTaskName);
//            }

        } else {
            status = taskNameBean.getTaskStatus();
        }
        JSONObject formJson = JSONObject.parseObject(formData);
        //把当前节点状态设置在 formData
        formJson.put(WorkFlowConstants.WORK_FLOW_TASK_STATUS_KEY, StringUtils.isNotBlank(status) ? status : taskName);
        bizTask.setState(StringUtils.isNotBlank(status) ? status : taskName);
        //添加编号字段
        formJson.put(WorkFlowConstants.WORK_FLOW_TASK_ID_KEY, taskCode);

        //添加签字异常类型
        if (WorkFlowExceptionStatusEnum.SIGN.getValue().equals(exceptionStatus)) {
            formJson.put(WorkFlowConstants.WORK_FLOW_EXCEPTION_STATUS, WorkFlowExceptionStatusEnum.SIGN.getDesc());
        }

        String key = bizTask.getAssignKey();
        String value = bizTask.getAssignValue();
        if (StringUtils.isNotEmpty(key) && StringUtils.isNotEmpty(value)) {
            if ("person".equals(key)) {
                value = baseUserDao.getRealNameById(Long.valueOf(value));
            } else if ("role".equals(key)) {
                BaseRole role = roleService.findById(Long.valueOf(value));
                if (role != null) {
                    value = role.getName();
                }
            } else if ("job".equals(key) || "post".equals(key)) {
                value = jobDao.getNameById(Long.valueOf(value));
            } else if ("department".equals(key)) {
                value = departDao.getNameById(Long.valueOf(value));
            }
            key = WorkFlowAssignKey.findNameByCode(key);
        }
        formJson.put(WorkFlowConstants.WORK_FLOW_TASK_NAME, bizTask.getTaskName());
        formJson.put(WorkFlowConstants.WORK_FLOW_ASSIGN_KEY, key);
        formJson.put(WorkFlowConstants.WORK_FLOW_ASSIGN_VALUE, value);
        if (formJson.get(WorkFlowConstants.WORK_FLOW_TASK_BIZNAME_KEY) == null) {
            formJson.put(WorkFlowConstants.WORK_FLOW_TASK_BIZNAME_KEY, bizTask.getBizName());
        }
        return formJson.toJSONString();

    }

    private static final ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(5, r -> {
        Thread thread = new Thread(r, "work safety job worker");
        thread.setDaemon(true);
        return thread;
    });


    /**
     * 提交当前任务节点
     *
     * @param taskBean
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultBean submitTask(WorkFlowExecuteTaskBean taskBean, HttpServletRequest request) throws ApiBusinessException {
        log.info("submitTask--------------->> 参数: {}", JSON.toJSONString(taskBean));
        WorkFlowTask bizTask = null;
        Task actTask = null;
        WorkFlowProcess process = workFlowProcessService.findById(taskBean.getWorkFlowProcessId()).get();
        Pair<List<String>, String> pair = getRiskAssessment(process.getFormJson());
        List<String> nodeList = pair.getKey();
        String riskAssessmentKey = pair.getValue();
        boolean riskLevelNeedChange = !CollectionUtils.isEmpty(nodeList);
        //用户操作类型
        final String operation = StringUtils.isEmpty(taskBean.getOperation()) && taskBean.getId() == null ? WorkFlowOperationEnum.APPLY.getValue() : taskBean.getOperation();

        //存在app，web端同一账号下的同一节点的重复动作
        if (taskBean.getId() != null && taskBean.getFormData() != null) {
            bizTask = workFlowTaskDao.findById(taskBean.getId()).orElseThrow(() -> new ApiBusinessException(Status.PROCESS_HAS_BEEN_PROCESSED));
            JSONObject jsonObject = JSONObject.parseObject(taskBean.getFormData());
            String name = jsonObject.getString(WorkFlowConstants.WORK_FLOW_TASK_NAME);
            String taskName = bizTask.getTaskName();
            if (!taskName.equals(name)) {
                log.error("{} 当前任务已经被处理！", taskName);
                throw new ApiBusinessException(Status.PROCESS_HAS_BEEN_PROCESSED);
            }
        }

        //1. 判断是否是第一个节点: 启动业务流程实例; 或者草稿
        if (taskBean.getId() == null || taskBean.getId() == 0) {
            bizTask = new WorkFlowTask();
            //设置编号与状态固定字段
            bizTask.setProcessId(taskBean.getWorkFlowProcessId());
            bizTask.setVarMapData(taskBean.getVarMap() == null ? "" : taskBean.getVarMap().toString());
            bizTask.setStatus(0);
            bizTask.setObjectId(taskBean.getObjectId());
            bizTask.setLevelName("无"); //处理整改报警
            bizTask.setPushTime(LocalDateTime.now());
            if (taskBean.getTypeId() != null) {
                bizTask.setTypeId(taskBean.getTypeId());
            }
            bizTask = workFlowTaskDao.save(bizTask);

            //启动业务流程实例, 并关联当前task id

            //根据业务流程definationId 启动流程， 并传入当前 任务节点ID做为 businessKey ，以备后续使用
            process = workFlowProcessService.findById(taskBean.getWorkFlowProcessId()).get();
            ProcessInstance instance = runtimeService.startProcessInstanceByKey(process.getDefinitionKey(), String.valueOf(bizTask.getId()), taskBean.getVarMap());
            log.info("创建业务流程实例 byID: " + instance.getId() + ", 业务流程：" + process.getBizName());

            actTask = taskService.createTaskQuery().processInstanceId(instance.getId()).processInstanceBusinessKey(String.valueOf(bizTask.getId())).singleResult();

            bizTask.setProcessId(process.getId());
            bizTask.setProcessInstanceId(instance.getProcessInstanceId());
            bizTask.setTaskId(actTask.getId());
        } else if (bizTask != null && WorkFlowStatusEnum.DRAFT.getValue().equals(bizTask.getStatus())) {
            bizTask.setVarMapData(taskBean.getVarMap() == null ? "" : taskBean.getVarMap().toString());
            bizTask.setStatus(0);
            bizTask.setObjectId(taskBean.getObjectId());
            if (taskBean.getTypeId() != null) {
                bizTask.setTypeId(taskBean.getTypeId());
            }
            bizTask = workFlowTaskDao.save(bizTask);

            //启动业务流程实例, 并关联当前task id

            //根据业务流程definationId 启动流程， 并传入当前 任务节点ID做为 businessKey ，以备后续使用
            process = workFlowProcessService.findById(taskBean.getWorkFlowProcessId()).get();
            ProcessInstance instance = runtimeService.startProcessInstanceByKey(process.getDefinitionKey(), String.valueOf(bizTask.getId()), taskBean.getVarMap());
            log.info("创建业务流程实例 byID: " + instance.getId() + ", 业务流程：" + process.getBizName());

            actTask = taskService.createTaskQuery().processInstanceId(instance.getId()).processInstanceBusinessKey(String.valueOf(bizTask.getId())).singleResult();

            bizTask.setProcessInstanceId(instance.getProcessInstanceId());
            bizTask.setTaskId(actTask.getId());
        } else {
            bizTask = bizTask != null ? bizTask : workFlowTaskDao.findById(taskBean.getId()).orElseThrow(() -> new ApiBusinessException(Status.PROCESS_HAS_BEEN_PROCESSED));
            actTask = taskService.createTaskQuery().taskId(bizTask.getTaskId()).singleResult();
            if (actTask == null) {
                throw new ApiBusinessException(Status.PROCESS_HAS_BEEN_PROCESSED);
            }
        }
        //设置业务类型字段
        bizTask.setBizName(process.getBizName());
        //如果编码为空，设置业务编码
        String taskCode = StringUtils.isEmpty(bizTask.getCode()) ? this.generateTaskCode(process) : bizTask.getCode();
        bizTask.setCode(taskCode);

        List<WorkFlowTaskNameBean> taskNameList = workFlowProcessService.findTaskNameList(taskBean.getWorkFlowProcessId());
        Map<String, WorkFlowTaskNameBean> taskNameMap = taskNameList.stream().collect(Collectors.
                toMap(WorkFlowTaskNameBean::getTaskName, Function.identity(), (i, j) -> i));

        //生成签字异常消息通知
        generateSignNotice(taskBean, bizTask.getBizName(), bizTask.getTaskName(), bizTask.getCode());

        //抽取数据权限字段值
        processDataAuth(bizTask, taskBean, process);

        //2. 执行 当前任务节点
        //设置参数并执行任务

        if (StringUtils.isEmpty(bizTask.getTaskName())) {
            bizTask.setTaskName(actTask.getName());
        }

        WorkFlowTaskNameBean taskNameBean = taskNameMap.get(bizTask.getTaskName());
        taskBean.getVarMap().put("bizId", bizTask.getId());

        //根据flowKey分流
        //前端常传无意义的实体，过滤
        //高处作业存在一个特殊的问题：某个审批节点过后经过一个网关后分三个支流
        //判断条件： param==0时走不通过支流，通过时需要根据分流条件进一步判断走剩下的哪个支流,
        Pair<Boolean, String> hasFlowKey = hasFlowKey(taskNameBean, taskBean);
        if (hasFlowKey.getKey()) {
            //此版本分流条件固定 level字段
            taskBean.getVarMap().put("level", hasFlowKey.getValue());
        }

        String exceptionStatus = taskBean.getExceptionStatus();

        //根据任务标识，判断任务走向
        if (taskNameBean == null || taskNameBean.getCountersign() == null || taskNameBean.getCountersign() == 0) {
            taskService.complete(actTask.getId(), taskBean.getVarMap());
        } else if (taskNameBean.getCountersign() == 1 || taskNameBean.getCountersign() == 2) {
            Map<String, Object> varMap = taskBean.getVarMap();
            Object o = varMap.get("param");
            Integer param = o == null ? 0 : Integer.parseInt(String.valueOf(o));
            bizTask.setParam(param);
            bizTask.setAssignKey("person");
            bizTask.setFormData(addStatus4FormData(taskBean.getFormData(), actTask.getName(), bizTask.getTaskName(), bizTask, taskNameList, taskCode, exceptionStatus));
            workFlowTaskDao.save(bizTask);
            //子任务
            List<WorkFlowTask> childTaskList = workFlowTaskDao.findByParentId(bizTask.getParentId());
            if (CollectionUtils.isNotEmpty(childTaskList)) {
                List<String> exceptionStatusList = childTaskList.stream().map(WorkFlowTask::getExceptionStatus).collect(Collectors.toList());
                if (exceptionStatusList.contains(WorkFlowExceptionStatusEnum.SIGN.getValue())) {
                    exceptionStatus = WorkFlowExceptionStatusEnum.SIGN.getValue();
                }
            }
            long noApproveCount = childTaskList.stream().filter(r -> r.getParam() == null).count();
            long passCount = childTaskList.stream().filter(r -> r.getParam() != null && r.getParam() == 1).count();
            if (taskNameBean.getCountersign() == 1) {
                //会签 一人不通过即不通过
                if (param == 0) {
                    varMap.put("param", 0);
                    finishTaskAndRemoveChildTask(actTask, varMap, childTaskList);
                } else {
                    //会签 全部通过才通过
                    //都审批
                    if (noApproveCount == 0) {
                        if (passCount != childTaskList.size()) {
                            varMap.put("param", 0);
                        }
                        //签字数据合并
                        List<ComponentStatisticBO> nodeSignCompList = findObjectFormJsonSignComponent(process.getFormJson(), bizTask.getTaskName());
                        log.info("---------------->current task sign component list :{}", JSONUtil.toJsonStr(nodeSignCompList));
                        String formData = mergeSignData(bizTask, childTaskList, nodeSignCompList);
                        taskBean.setFormData(formData);
                        finishTaskAndRemoveChildTask(actTask, varMap, childTaskList);
                    } else {
                        //3.  检查是否保存 当前节点历史记录
                        checkTaskExecute(actTask.getName(), bizTask.getId(), taskBean.getFormData(), taskNameList, process.getFormKeyLabelJson());
                        //风险等级change
                        if (riskLevelNeedChange) {
                            riskLevelChange(bizTask.getCode(), bizTask.getTaskName(), nodeList, bizTask.getFormData(), riskAssessmentKey);
                        }
                        //保存流转日志
                        insertTaskAssignHistory(actTask.getName(), Long.valueOf(bizTask.getTaskId()), operation, null, null, null, taskCode, taskBean.getRemark());
                        // 大屏刷新
                        bigScreenRefresh(bizTask.getBizName());
                        return ResultBean.defaultSuccessResult();
                    }
                }
            } else {
                //或签 一人通过即通过，一人不通过即不通过
                varMap.put("param", param);
                finishTaskAndRemoveChildTask(actTask, varMap, childTaskList);
            }
        }

        //3.  检查是否保存 当前节点历史记录
        checkTaskExecute(actTask.getName(), bizTask.getId(), taskBean.getFormData(), taskNameList, process.getFormKeyLabelJson());

        //调用API接口， 同步隐患登记
        hiddenDangerSender.addHiddenDanger(taskBean.getFormData(), actTask.getName(), process.getFormKeyLabelJson(), request);

        //调用API 接口
        workFlowAPIService.sendData(taskBean.getFormData(), actTask.getName(), process.getFormKeyLabelJson(), request);

        //4. 查询下个节点信息，设置下个节点 指派人员信息 assignKey, assignValue
        Task nextActTask = taskService.createTaskQuery().executionId(actTask.getExecutionId()).singleResult();
        //找到父任务
        Long parentId = bizTask.getParentId();
        if (parentId != null && parentId != 0) {
            bizTask = workFlowTaskDao.findById(parentId).orElseThrow(() -> new IllegalArgumentException("此任务已被删除"));
        }
        //动态风险
        if (process.getBizTypeName().equals("作业票")) {
            workFlowTaskDynamicService.saveDynamicRecords(process.getId(), process.getFormJson(), bizTask.getCode(), bizTask.getTaskName(), taskBean.getFormData(), nextActTask != null);
        }
        if (nextActTask == null) {
            bizTask.setStatus(1);
            WorkFlowTaskNameBean endTask = taskNameList.stream().filter(item -> item.getCompleteStatus() == 1).collect(Collectors.toList()).get(0);
            bizTask.setTaskName(endTask.getTaskName());
            // 隐患治理完成时恢复计划状态
            if (WorkFlowTaskRefSource.YHPC.getSource().equals(bizTask.getRefSource())) {
                investigateRecordService.changePlanInvalid(bizTask.getRefDetailId(), "submitTask");
            } else if (WorkFlowTaskRefSource.ZNXJ.getSource().equals(bizTask.getRefSource())) {
                // 智能巡检
                patrolRecordItemService.repairFinish(bizTask.getRefDetailId());
            } else if (WorkFlowTaskRefSource.AQBBZRZ.getSource().equals(bizTask.getRefSource())) {
                MhMajorHazardTaskRecordItem recordItem = mhMajorHazardTaskRecordItemService.getById(bizTask.getRefDetailId());
                recordItem.setNodeFlag(1);
                mhMajorHazardTaskRecordItemService.saveOrUpdate(recordItem);
                MhMajorHazardTaskRecord record = mhMajorHazardTaskRecordService.getById(recordItem.getRecordId());
                List<MhMajorHazardTaskRecordItem> items = mhMajorHazardTaskRecordItemService.findByRecordIdAndResult(record.getId(), 0);
                List<Integer> nodeFlagList = items.stream().map(MhMajorHazardTaskRecordItem::getNodeFlag).distinct().collect(Collectors.toList());
                if (CollectionUtils.isNotEmpty(nodeFlagList) && !nodeFlagList.contains(0)) {
                    record.setExcepHandle(3);
                    record.setStatus(1);
                }
                int a = 0;
                int b = 0;
                for (MhMajorHazardTaskRecordItem item : items) {
                    if (item.getWorkFlowTaskId() == null) {
                        a++;

                    } else if (item.getWorkFlowTaskId() != null && item.getNodeFlag().intValue() == 0) {
                        b++;
                    }
                }
                if (a == 0 && b != 0) {
                    record.setExcepHandle(2);
                    record.setStatus(0);
                } else if (a != 0) {
                    record.setExcepHandle(0);
                    record.setStatus(0);
                }
                mhMajorHazardTaskRecordService.saveOrUpdate(record);
            }
        } else {
            bizTask.setTaskId(nextActTask.getId());
            bizTask.setTaskName(nextActTask.getName());
        }
        //设置任务的前节点
        bizTask.setPreTaskName(actTask.getName());
        bizTask.setVarMapData(taskBean.getVarMap() == null ? "" : taskBean.getVarMap().toString());
        bizTask.setObjectId(taskBean.getObjectId());
        //没有后续任务节点，则流程执行完成
        if (nextActTask == null) {
            //任务结束，之前的处理是取结束节点的assignKey，并且修改formData中的指派人等字段
            //bizTask.setAssignValue("-1".equals(bizTask.getAssignValue()) ? null : bizTask.getAssignValue());
            bizTask.setAssignKey(null);
            bizTask.setAssignValue(null);
            //设置编号与状态固定字段
            bizTask.setFormData(addStatus4FormData(taskBean.getFormData(), actTask.getName(), bizTask.getTaskName(), bizTask, taskNameList, taskCode, exceptionStatus));
            workFlowTaskDao.save(bizTask);
            //保存流程流转记录
            insertTaskAssignHistory(actTask.getName(), Long.valueOf(bizTask.getTaskId()), operation, null, null, null, taskCode, taskBean.getRemark());
            //作业围栏报警
            railAlarm(bizTask.getTaskName(), bizTask, taskBean.getFormData(), true);
            //风险等级change
            if (riskLevelNeedChange) {
                //结束节点前一个节点不管是升高还是降低，最终都立马走向结束节点，用户根本无法感知此节点带来的变化
                //走结束节点
                riskLevelChange(bizTask.getCode(), bizTask.getTaskName(), nodeList, bizTask.getFormData(), riskAssessmentKey);
            }
            //删除未发送的通知提醒
            noticeWaitingTriggerListService.deleteNotTriggered(bizTask.getCode());
            if (Constant.SYNC_ON == process.getSyncStatusOnOff()) {
                workFlowTaskProcessListService.saveStatisticData(bizTask.getId(), bizTask.getProcessId(), bizTask.getCode(), bizTask.getFormData(), bizTask.getAuthType(), bizTask.getAuthValue(), Context.getCurrentTenantId(), Context.getCompanyCode());
            }
            // 大屏刷新
            bigScreenRefresh(bizTask.getBizName());
            return ResultBean.defaultSuccessResult();
        }
        //获取下一个节点指定人员/部门/岗位/角色/指定组件信息
        WorkFlowTaskNameBean taskConfig = getCurTaskConfig(taskBean.getWorkFlowProcessId(), bizTask.getTaskName());
        Integer curCountersign = null;
        if (taskConfig != null) {
            curCountersign = taskConfig.getCountersign();
        }
        List<CountersignBean> countersignList = getAssignMap(bizTask.getTaskName(), taskBean.getObjectId(), taskBean.getVarMap(), bizTask.getId(), taskConfig);

        WorkFlowTaskNameBean workFlowTaskNameBean = taskNameMap.get(nextActTask.getName());
        //流程节点配置错误增加提醒
        if (workFlowTaskNameBean == null) {
            log.error("Process node config error,the next task {} was not found,taskNameMap {}", nextActTask.getName(), JSON.toJSONString(taskNameMap));
            throw new ApiBusinessException(Status.PROCESS_NODE_CONFIG_ERROR);
        }
        Integer countersign = workFlowTaskNameBean.getCountersign();

        //设置编号与状态固定字段
        bizTask.setFormData(addStatus4FormData(taskBean.getFormData(), actTask.getName(), bizTask.getTaskName(), bizTask, taskNameList, taskCode, exceptionStatus));
        if (countersign == null || countersign == 0) {
            CountersignBean countersignBean = countersignList.get(0);
            bizTask.setAssignKey(countersignBean.getAssignKey());
            bizTask.setAssignValue(countersignBean.getAssignValue());
            bizTask.setFormData(addStatus4FormData(taskBean.getFormData(), actTask.getName(), bizTask.getTaskName(), bizTask, taskNameList, taskCode, exceptionStatus));
            bizTask.setPreTaskName(actTask.getName());
            //签字异常,整个流转过程存在一次即异常，后期可将异常拆出来作为独立模块
            if (WorkFlowExceptionStatusEnum.SIGN.getValue().equals(exceptionStatus)) {
                bizTask.setExceptionStatus(exceptionStatus);
            }
            workFlowTaskDao.save(bizTask);
        } else if (countersign == 1 || countersign == 2) {
            //会签/或签任务
            //1.父任务设置assign_value -1 避免查询
            //2.新增子任务
            for (CountersignBean bean : countersignList) {
                WorkFlowTask childTask = newChildTask(bizTask, bean);
                childTask = workFlowTaskDao.save(childTask);
                childTask.setFormData(addStatus4FormData(childTask.getFormData(), actTask.getName(), childTask.getTaskName(), childTask, taskNameList, taskCode, exceptionStatus));
                childTask.setCreateBy(bizTask.getCreateBy());
                workFlowTaskDao.save(childTask);
            }
            //签字异常,整个流转过程存在一次即异常，后期可将异常拆出来作为独立模块
            if (WorkFlowExceptionStatusEnum.SIGN.getValue().equals(exceptionStatus)) {
                bizTask.setExceptionStatus(exceptionStatus);
            }
            bizTask.setAssignValue(String.valueOf(-1));
            workFlowTaskDao.save(bizTask);
        }
        //保存流转历史记录
        saveTaskAssignHistoryByCountersignType(actTask.getName(), Long.valueOf(bizTask.getTaskId()), operation, countersignList, curCountersign, nextActTask.getName(), taskCode, taskBean.getRemark());
        //作业围栏报警
        bizTask.setBizName(process.getBizName());
        railAlarm(actTask.getName(), bizTask, taskBean.getFormData(), false);
        //风险等级change
        if (riskLevelNeedChange) {
            riskLevelChange(bizTask.getCode(), actTask.getName(), nodeList, bizTask.getFormData(), riskAssessmentKey);
        }
        // 大屏刷新
        bigScreenRefresh(bizTask.getBizName());
        //推送待办信息
        pushToDoMsg(countersignList, bizTask.getAuthType(), bizTask.getAuthValue(), nextActTask.getName(), bizTask.getCode(), bizTask.getId(), process.getBizName());
        //分析提醒
        processNoticeListService.generateNotice(bizTask.getProcessId(), bizTask.getCode(), process.getBizName(), bizTask.getFormData(), bizTask.getObjectId());
        //解析统计字段
        if (Constant.SYNC_ON == process.getSyncStatusOnOff()) {
            workFlowTaskProcessListService.saveStatisticData(bizTask.getId(), bizTask.getProcessId(), bizTask.getCode(), bizTask.getFormData(),
                    bizTask.getAuthType(), bizTask.getAuthValue(), Context.getCurrentTenantId(), Context.getCompanyCode());
        }
        return ResultBean.defaultSuccessResult();
    }

    private String mergeSignData(WorkFlowTask bizTask, List<WorkFlowTask> childTaskList, List<ComponentStatisticBO> nodeSignCompList) {
        String formData = bizTask.getFormData();
        for (WorkFlowTask task : childTaskList) {
            if (!task.getId().equals(bizTask.getId())) {
                JSONObject curTaskFormData = JSON.parseObject(formData);
                for (ComponentStatisticBO sign : nodeSignCompList) {
                    Object curSignObject = curTaskFormData.get(sign.getKey());
                    if (curSignObject != null) {
                        JSONObject curSignJson = JSON.parseObject(curSignObject.toString());
                        Object curOperatorSignObj = curSignJson.get(WorkFlowConstants.FROM_JSON_KEY_SIGN);
                        if (JSONUtil.isJsonArray(curOperatorSignObj.toString())) {
                            JSONArray curSignArray = JSON.parseArray(curOperatorSignObj.toString());
                            JSONObject otherTaskFormData = JSON.parseObject(task.getFormData());
                            Object otherSignObject = otherTaskFormData.get(sign.getKey());
                            if (otherSignObject != null) {
                                JSONObject otherSignJson = JSON.parseObject(otherSignObject.toString());
                                Object otherOperatorSignObj = otherSignJson.get(WorkFlowConstants.FROM_JSON_KEY_SIGN);
                                JSONArray otherSignArray = JSON.parseArray(otherOperatorSignObj.toString());
                                curSignArray.addAll(otherSignArray);
                                curSignJson.put(WorkFlowConstants.FROM_JSON_KEY_SIGN,curSignArray);
                                curTaskFormData.put(sign.getKey(),curSignJson);
                            }
                        }
                    }
                }
                formData = curTaskFormData.toJSONString();
            }
        }
        return formData;
    }

    void bigScreenRefresh(String bizName) {
        // 第三个参数应是bizName，目前需要全量推，故用null
        try {
            monitorPointDataWebSocketService.getWorkflowView(Context.getCompanyCode(), Context.getCurrentTenantId(), null);
        } catch (Throwable e) {
            log.error("bigScreenRefresh fail:", e);
        }
    }

    public List<ComponentStatisticBO> findObjectFormJsonSignComponent(String formJsonStr, String nodeName) {
        List<ComponentStatisticBO> components = new ArrayList<>();
        //合并组件列表，先实现签字
        if (StringUtils.isNotBlank(formJsonStr)) {
            JSONObject formJson = JSON.parseObject(formJsonStr);
            Object temArrObj = formJson.get(WorkFlowConstants.FROM_JSON_KEY_TEMARR);
            if (temArrObj != null) {
                JSONArray temArr = JSONObject.parseArray(temArrObj.toString());
                for (Object tem : temArr) {
                    Map<String, Object> tableMap = JSONObject.parseObject(JSON.toJSONString(tem));
                    Object column1 = tableMap.get(WorkFlowConstants.FROM_JSON_KEY_COLUMN1);
                    if (WorkFlowConstants.FROM_JSON_KEY_TABLE.equals(column1)) {
                        continue;
                    }
                    Object tableArrObj = tableMap.get(WorkFlowConstants.FROM_JSON_KEY_TABLEARR);
                    JSONArray tableArr = JSONObject.parseArray(tableArrObj.toString());
                    for (Object table : tableArr) {
                        Map<String, Object> beanMap = JSONObject.parseObject(JSON.toJSONString(table));
                        Object typeObj = beanMap.get(WorkFlowConstants.FROM_JSON_KEY_TYPE);
                        if (typeObj != null) {
                            String value = (String) typeObj;
                            if (WorkFlowConstants.FROM_JSON_TYPE_SIGN.equals(value)) {
                                Object labelObj = beanMap.get(WorkFlowConstants.FROM_JSON_KEY_LABEL);
                                Object selfObj = beanMap.get(WorkFlowConstants.FROM_JSON_KEY_SELF);
                                Object nodeWriteProp = beanMap.get(nodeName);
                                if (nodeWriteProp != null) {
                                    List<String> writeProps = Arrays.asList("1", "2", "3", "4");
                                    if (writeProps.contains(nodeWriteProp.toString())) {
                                        components.add(new ComponentStatisticBO(null, (String) typeObj, (String) labelObj, (String) selfObj));
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        return components;
    }

    private void pushToDoMsg(List<CountersignBean> countersignList, String authType, String authValue, String nextActTaskName, String taskCode, Long taskId, String bizName) {
        List<String> userIdStrList = countersignList.stream().map(CountersignBean::getAssignValue).filter(StringUtils::isNotBlank).collect(Collectors.toList());
        Set<Long> userIds = userIdStrList.stream().map(s -> Long.parseLong(s.trim())).collect(Collectors.toSet());
        if (CollectionUtils.isEmpty(userIds)) {
            if (StringUtils.isNotBlank(authType) && StringUtils.isNotBlank(authValue)) {
                String[] idArray = authValue.split(Constant.SPLIT_COMMA);
                List<Long> departIds = Arrays.stream(idArray).map(Long::parseLong).collect(Collectors.toList());
                if (CollectionUtils.isNotEmpty(departIds)) {
                    List<Long> userIdList = baseUserDao.findIdByDepartIdIn(departIds);
                    userIds.addAll(userIdList);
                }
            }
        }
        if (CollectionUtils.isNotEmpty(userIds)) {
            BaseConfig todoMessageConfig = baseConfigService.findFirstConfig(BaseConfigCodes.PROCESS_TO_DO_MESSAGE);
            if (todoMessageConfig != null) {
                String msg = todoMessageConfig.getValue();
                noticeWaitingTriggerListService.save(userIds, nextActTaskName, String.format(msg, bizName, nextActTaskName), BusinessTypeEnum.FLOW.getBusinessCode(), taskCode, new Date());
                // app通知中心
                ArrayList<CommonBusinessNotice> commonBusinessNotices = new ArrayList<>();
                for (Long userId : userIds) {
                    CommonBusinessNotice appNotify = new CommonBusinessNotice();
                    appNotify.setBusinessType(AppBusinessNoticeTypes.FLOW.getType())
                            .setNoticeContent(MessageFormat.format(String.format(msg, bizName, nextActTaskName), baseUserDao.getRealNameById(userId)))
                            .setNoticeUser(userId)
                            .setNoticeTitle(AppNotifyContentPre.FLOW_NOTIFY)
                            .setSendTime(new Date())
                            .setRefId(taskId);
                    commonBusinessNotices.add(appNotify);
                }
                commonBusinessNoticeService.saveBatch(commonBusinessNotices);
            }
        }
    }

    /**
     * 根据数据权限字段配置，抽取数据权限值
     */

    private void processDataAuth(WorkFlowTask bizTask, WorkFlowExecuteTaskBean taskBean, WorkFlowProcess process) {
        if (process.getAuthConfig() != null) {
            List<WorkFlowAuthConfigDto> list = JSONArray.parseArray(process.getAuthConfig(), WorkFlowAuthConfigDto.class);
            if (list != null && list.size() > 0) {
                WorkFlowAuthConfigDto authConfig = list.get(0);
                bizTask.setAuthType(authConfig.getType());
                if (authConfig.getKey() == null) {
                    bizTask.setAuthValue(null);
                    return;
                }
                //解析JSONObject， 获取key 对应的 ID
                // 数据格式： {"key_9c4d00548ddd4c738665e13b56901836":[{"id":228,"flag":0}],"key_5b6ae48a26aa47848e7c7fb32e486c38":[{"id":9784,"flag":0}],"key_fa51cc91a7c449f9a001913f5ff81efa":[{"id":182,"flag":0}]}
                JSONObject fieldIds = JSONObject.parseObject(taskBean.getObjectId());
                if (fieldIds == null) {
                    bizTask.setAuthValue(null);
                } else {
                    JSONArray jsonArray = fieldIds.getJSONArray(authConfig.getKey());
                    if (jsonArray == null) {
                        bizTask.setAuthValue(null);
                    } else {
                        StringBuilder sb = new StringBuilder();
                        jsonArray.forEach(each -> {
                            if (sb.length() > 0) {
                                sb.append(Constant.SPLIT_COMMA);
                            }
                            JSONObject json = (JSONObject) each;
                            sb.append(json.get(Constant.FROM_DATA_ID_KEY));
                        });
                        bizTask.setAuthValue(sb.toString());
                    }
                }
            }
        }
    }


    /**
     * 生成签字异常消息提醒
     *
     * @param taskBean
     */
    private void generateSignNotice(WorkFlowExecuteTaskBean taskBean, String notifyType, String taskName, String code) {
        if (taskBean.getNoticeInfo() != null) {
            List<WorkFlowSignNoticeBean> signNoticeList = taskBean.getNoticeInfo();
            Map<Long, List<String>> receiveMap = new HashMap<Long, List<String>>();
            for (WorkFlowSignNoticeBean signNotice : signNoticeList) {
                if (signNotice.isFlag_location_exception() && signNotice.isFlag_need_notice()) {

                    if (signNotice.getNotice_receiver_list() != null) {
                        for (NoticeReceiver receiver : signNotice.getNotice_receiver_list()) {
                            //提醒类型是人员
                            if ("person".equalsIgnoreCase(receiver.getType())) {
                                // 按提醒人把签字人进行分组
                                if (receiveMap.containsKey(receiver.getValue())) {
                                    List<String> userList = receiveMap.get(receiver.getValue());
                                    if (!userList.contains(signNotice.getKey_operation_person())) {
                                        userList.add(signNotice.getKey_operation_person());
                                    }
                                } else {
                                    List<String> userList = new ArrayList<>();
                                    userList.add(signNotice.getKey_operation_person());
                                }

                            }

                        }
                    }

                }
            }
            processNoticeMessage(receiveMap, notifyType, taskName, code);
        }
    }

    private void processNoticeMessage(Map<Long, List<String>> receiveMap, String notifyType, String taskName, String code) {
        List<CommonIndexNotify> notifyList = new ArrayList<>();
        receiveMap.forEach((key, value) -> {
            StringBuilder msg = new StringBuilder();
            CommonIndexNotify notify = new CommonIndexNotify();
            notify.setType(notifyType);
            notify.setReadFlag(0);
            notify.setQueueOrNot(0);
            notify.setRemindedOrNot(1);
            notify.setUserId(key);
            //消息提醒格式：【作业编号】在【流程节点】时， 【人员姓名】签名时未在规定区域内。
            msg.append(code).append("在").append(taskName).append("时，\"").append(value).append("\" 签名时未在规定区域内。");
            notify.setNotifyMessage(msg.toString());
            notifyList.add(notify);
        });

        commonIndexNotifyDao.saveAll(notifyList);


    }

    /**
     * 获取风险评估组件配置的节点
     * key: 节点集合， value: 组件key
     */
    public Pair<List<String>, String> getRiskAssessment(String formJson) {
        JSONObject formObject = JSONObject.parseObject(formJson);
        JSONArray temArr = formObject.getJSONArray("temArr");
        for (Object o : temArr) {
            JSONObject jsonObject = (JSONObject) o;
            JSONArray tableArr = jsonObject.getJSONArray("tableArr");
            if (tableArr != null) {
                for (Object o1 : tableArr) {
                    JSONObject tableObject = (JSONObject) o1;
                    JSONObject specialObject = tableObject.getJSONObject("special");
                    if (specialObject != null) {
                        JSONObject riskAssessmentObject = specialObject.getJSONObject("riskAssessment");
                        if (riskAssessmentObject != null) {
                            JSONArray processNodeArr = riskAssessmentObject.getJSONArray("processNode");
                            if (processNodeArr != null) {
                                String key = tableObject.getString("key");
                                return new Pair<>(processNodeArr.toJavaList(String.class), key);
                            }
                        }
                    }
                }
            }
        }
        return new Pair<>(Lists.newArrayList(), "");
    }

    /**
     * 作业票风险评估，作业流经配置的节点需要相应提高区域风险等级
     * 走到未配置的节点，需要相应降低区域风险等级
     * formData中无风险评估相关信息，不调接口
     */
    private void riskLevelChange(String code, String actTaskName, List<String> nodeList, String formData, String riskAssessmentKey) {
        JSONObject formObject = JSONObject.parseObject(formData);
        JSONObject riskObject = formObject.getJSONObject(riskAssessmentKey);
        if (riskObject == null) {
            log.info("作业票风险评估，formData中无风险评估信息, riskKey:{}", riskAssessmentKey);
            return;
        }
        Long riskPointId = riskObject.getLong("riskPointId");
        Long riskDistrictId = riskObject.getLong("riskDistrictId");
        Long riskEvaluationId = riskObject.getLong("riskEvaluationId");
        if (riskPointId == null || riskDistrictId == null) {
            log.info("作业票风险评估，riskPointId = null or riskDistrictId = null");
            return;
        }
        int flag = nodeList.contains(actTaskName) ? 1 : 0;
        riskEvaluationBusinessService.changeDistrictLevelFromLibraryPoint(riskEvaluationId, riskDistrictId,
                flag, code);
        log.info("作业票风险评估，流程流经:{},风险等级{} success", actTaskName, flag == 1 ? "升高" : "降低");
    }


    /**
     * 作业围栏报警
     * 调人员在岗在位   新增/修改作业区域接口
     * 化工那边根据作业证编号是否存在判断新增/修改
     */
    private void railAlarm(String taskName, WorkFlowTask bizTask, String formData, boolean isTaskEnd) {
        ShiroUser currentUser = Context.getCurrentUser();
        executor.execute(() -> {
            try {
                Context.setCurrentUser(currentUser);
                Long processId = bizTask.getProcessId();
                WorkFlowProcess process = processDao.findById(processId).get();
                if (process.getLocationServiceOpen()== null || !process.getLocationServiceOpen().booleanValue()) {
                    return;
                }
                WorkFlowLocationConfig locationConfig = locationConfigDao.findFirstByProcessId(processId);
                if (locationConfig == null || !locationConfig.isRailAlarmOpen()){
                    return;
                }
                log.info("电子围栏报警-推送判断开始...");
                WorkFlowRailAlarmConfig railAlarmConfig = railAlarmConfigDao.findFirstByProcessId(processId);
                if (railAlarmConfig == null) return;
                log.info("电子围栏报警-配置通过...");
                //这版暂不处理时间组件范围
                if (!WorkFlowShowTypes.FLOW_NODE_RANGE.getType().equals(railAlarmConfig.getEffectiveTime())) {
                    log.info("电子围栏报警-非流程节点范围 pass ...");
                }
                String buildId = locateServerService.getBuildId();
                if (buildId == null) {
                    log.error("人员在岗在位没配置buildId");
                    return;
                }

                //结束节点，修改数据，将离岗报警和闯入报警两个开关都置位false
                if (railAlarmConfig.getEndNode().equals(taskName) || isTaskEnd) {
                    Long id = bizTask.getParentId() != 0 ? bizTask.getParentId() : bizTask.getId();
                    WorkFlowRailAlarmTask alarmTask = railAlarmTaskDao.findFirstByTaskId(id);
                    if (alarmTask == null) {
                        log.error("电子围栏报警-结束节点删除数据-alarmTask数据查不到或uniqueId为空, id:" + alarmTask.getId());
                        return;
                    }
                    WorkRailAlarmBean bean = JSON.parseObject(alarmTask.getData(), WorkRailAlarmBean.class);
                    bean.setCheckOtherPersonIn(0);
                    bean.setCheckJobPersonOut(0);
                    bean.setUniqueId(alarmTask.getUniqueId());
                    bean.setJobContent(bizTask.getBizName());
                    bean.setJobNumber(bizTask.getCode());
                    bean.setJobEndTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern(DateTimeUtil.FORMAT_DEFAULT)));
                    String result = locateServerService.workArea(bean, 1);
                    //数据表数据置位
                    if (result != null) {
                        log.error("电子围栏报警-结束节点修改数据成功, id:" + alarmTask.getId());
                        alarmTask.setStatus(3);
                    } else {
                        log.error("电子围栏报警-结束节点修改数据失败, id:" + alarmTask.getId());
                        alarmTask.setStatus(4);
                    }
                    railAlarmTaskDao.save(alarmTask);
                }
                //开始节点，新增数据
                else if (railAlarmConfig.getStartNode().equals(taskName)) {
//                else if (taskName.contains("申请")) {
                    //过滤多个子任务提交导致的重复新增数据
                    Long parentId = bizTask.getParentId();
                    if (parentId != null && parentId != 0) {
                        WorkFlowRailAlarmTask alarmTask = railAlarmTaskDao.findFirstByTaskId(parentId);
                        if (alarmTask != null) {
                            log.info("电子围栏报警-过滤第二个子任务后的提交...");
                            return;
                        }
                    }

                    //准备数据
                    WorkRailAlarmBean bean = getRailAlarmBean(bizTask, formData, process, railAlarmConfig);
                    bean.setBuildId(buildId);
                    bean.setCheckOtherPersonIn(railAlarmConfig.isPermitEnter() ? 1 : 0);
                    bean.setCheckJobPersonOut(railAlarmConfig.isLeaveAlarm() ? 1 : 0);
                    bean.setJobContent(bizTask.getBizName());
                    bean.setJobNumber(bizTask.getCode());
                    String uniqueId = locateServerService.workArea(bean, 0);
                    WorkFlowRailAlarmTask railAlarmTask = new WorkFlowRailAlarmTask();
                    //使用父任务Id
                    railAlarmTask.setTaskId(bizTask.getParentId() != 0 ? bizTask.getParentId() : bizTask.getId());
                    railAlarmTask.setUniqueId(uniqueId);
                    railAlarmTask.setData(JSON.toJSONString(bean));
                    if (uniqueId != null) {
                        railAlarmTask.setStatus(1);
                        log.error("人员在岗在位新增作业区域接口调用成功");
                    } else {
                        railAlarmTask.setStatus(2);
                        log.error("人员在岗在位新增作业区域接口调用失败");
                    }
                    railAlarmTaskDao.save(railAlarmTask);
                }
            } catch (Exception e) {
                log.error("电子围栏报警-接口调用失败", e);
            }
        });
    }

    /**
     * 作业票删除
     *
     * @param bizTask
     * @return
     */
    public void railAlarmDelete(WorkFlowTask bizTask) {
        try {
            Long id = bizTask.getParentId() != 0 ? bizTask.getParentId() : bizTask.getId();
            WorkFlowRailAlarmTask alarmTask = railAlarmTaskDao.findFirstByTaskId(id);
            if (alarmTask == null) {
                return;
            }
            String uniqueId = alarmTask.getUniqueId();
            String buildId = locateServerService.getBuildId();
            if (buildId == null) {
                throw new IllegalArgumentException("作废失败，建筑信息未配置。");
            }
            if (uniqueId != null) {
                WorkRailAlarmDeleteBean deleteBean = new WorkRailAlarmDeleteBean();
                deleteBean.setBuildId(buildId);
                List<String> list = Lists.newArrayList();
                list.add(uniqueId);
                deleteBean.setUniqueIds(list);
                //调接口
                String result = locateServerService.workArea(deleteBean, 2);
                //数据表数据置位
                if (result != null) {
                    log.error("电子围栏报警-删除作业区域成功, id:" + alarmTask.getId());
                    alarmTask.setStatus(3);
                } else {
                    log.error("电子围栏报警-删除作业区域失败, id:" + alarmTask.getId());
                    alarmTask.setStatus(4);
                }
            } else {
                //uniqueId为空，说明未同步或者同步失败
                alarmTask.setStatus(5);
            }
            railAlarmTaskDao.save(alarmTask);
        } catch (Exception e) {
            throw new IllegalArgumentException("作废失败，请稍后尝试。");
        }
    }


    public WorkRailAlarmBean getRailAlarmBean(WorkFlowTask bizTask, String formData,
                                              WorkFlowProcess process, WorkFlowRailAlarmConfig railAlarmConfig) {
        WorkRailAlarmBean bean = new WorkRailAlarmBean();
        //小英：作业开始时间取当前时间；结束时间取三天后
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime localDateTime = now.plusDays(3);
        DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        bean.setJobStartTime(now.format(timeFormatter));
        bean.setJobEndTime(localDateTime.format(timeFormatter));
        //调接口新增
        //作业类型  两边作业类型名称不一致需要转
        String bizName = process.getBizName();
        bizName = covertWorkType(bizName);
        bean.setJobName(bizName);
        String formKeyLabelJson = process.getFormKeyLabelJson();
        String objectId = bizTask.getObjectId();
        JSONObject objectIdObject = JSONObject.parseObject(objectId);
        String alarmRule = railAlarmConfig.getAlarmRule();
        if (formKeyLabelJson != null) {
            JSONObject jsonObject = JSONObject.parseObject(formKeyLabelJson);
            //坐标点位  {"x":119.7557244776212,"y":34.34679261944328,"floorId":1}
            // String mapLocationKey = jsonObject.getString("地图位置");

            //坐标区域优化： 地图坐标key  从流程配置中获取，不再固定取标签名称 为“地图位置”, 同时处理 点+半径 的区域转换
            String mapLocationKey = jsonObject.getString("地图位置");
            WorkFlowLocationConfig locationConfig = locationConfigDao.findFirstByProcessId(process.getId());
            if (locationConfig != null) {
                mapLocationKey = locationConfig.getComponentKeyName();
            }
            //String locationKey = jsonObject.getString("作业人员");
            String workLevelKey = jsonObject.getString("作业级别");
            String applyDepartKey = jsonObject.getString("申请单位");
            String applyUserKey = jsonObject.getString("申请人");
            String actionEnsureKey = jsonObject.getString("措施确认");
            List<WorkRailAlarmMarkerBean> markerPosition = Lists.newArrayList();
            List<WorkRailAlarmUserBean> jobPersonJson = Lists.newArrayList();
            List<WorkRailAlarmSecurityBean> securityBeans = Lists.newArrayList();
            if (formData != null) {
                JSONObject parseObject = JSONObject.parseObject(formData);
                //坐标点位
                if (mapLocationKey != null) {
                    try {
                        JSONObject mapJsonObject = parseObject.getJSONObject(mapLocationKey);
                        if (mapJsonObject != null) {
                            // 先取圆形区域点位
                            JSONArray points = mapJsonObject.getJSONArray("circlePoints");
                            // 圆形点位列表空则 取 points
                            if (points == null || points.size() == 0) {
                                points = mapJsonObject.getJSONArray("points");
                            }
                            //2.11 兼容points内无楼层的情况
                            String floorId = null;
                            if (StringUtils.isNotBlank(mapJsonObject.getString("floorId"))) {
                                floorId = mapJsonObject.getString("floorId");
                            }
                            for (Object o : points) {
                                JSONObject jsonObject2 = (JSONObject) o;
                                markerPosition.add(getAlarmMarkerBean(jsonObject2, floorId));
                            }
                        }
                    } catch (Exception e) {
                        log.error("作业票点位解析失败 {}：", parseObject.toJSONString(), e);
                    }
                }
                //作业人员-取报警规则
                JSONArray jsonArray = JSONArray.parseArray(alarmRule);
                for (Object o : jsonArray) {
                    JSONObject jsonObject1 = (JSONObject) o;
                    jobPersonJson.addAll(getAlarmUserBean(jsonObject1, objectIdObject));
                }
                //去重
                jobPersonJson = jobPersonJson.stream().filter(r -> r.getUniqueId() != null)
                        .distinct().collect(Collectors.toList());
//                if (locationKey != null) {
//                    JSONArray jsonArray = parseObject.getJSONArray(locationKey);
//                    for (Object o : jsonArray) {
//                        JSONObject jsonObject1 = (JSONObject) o;
//                        jobPersonJson.add(getAlarmUserBean(jsonObject1));
//                    }
//                }
                //作业级别
                if (StringUtils.isNotBlank(workLevelKey)) {
                    String workLevel = parseObject.getString(workLevelKey);
                    bean.setJobLevel(workLevel);
                } else {
                    bean.setJobLevel("一级");
                }
                //作业编号
                String code = parseObject.getString("code");
                /*if (code == null) {
                    code = setCodeDetail(process.getCodePrefix(), bizTask);
                }*/
                bean.setJobNumber(code);
                //申请单位
                if (applyDepartKey != null) {
                    String depart = parseObject.getString(applyDepartKey);
                    if (JSONUtil.isJsonArray(depart)) {
                        StringBuilder valueBuilder = new StringBuilder();
                        JSONArray departArr = JSONObject.parseArray(depart);
                        for (Object departStr : departArr) {
                            if (valueBuilder.length() > 0) {
                                valueBuilder.append(Constant.SPLIT_COMMA);
                            }
                            JSONObject departObject = JSONObject.parseObject(departStr.toString());
                            valueBuilder.append(departObject.get("label"));
                        }
                        bean.setApplicationUnit(valueBuilder.length() > 0 ? valueBuilder.toString() : "未输入");
                    } else {
                        bean.setApplicationUnit(parseObject.getString(applyDepartKey));
                    }
                }
                //申请人
                if (applyUserKey != null) {
                    bean.setApplicationPerson(parseObject.getString(applyUserKey));
                    JSONArray jsonArray1 = objectIdObject.getJSONArray(applyUserKey);
                    if (jsonArray1 != null) {
                        JSONObject jsonObject1 = (JSONObject) jsonArray1.get(0);
                        Long id = jsonObject1.getLong("id");
                        //申请人不会是承包商
                        baseUserDao.findById(id).ifPresent(r -> bean.setApplicationPersonUniqueId(r.getUniqueId()));
                    }
                }
                //措施确认
                if (actionEnsureKey != null) {
                    JSONArray array = parseObject.getJSONArray(actionEnsureKey);
                    for (Object o : array) {
                        JSONObject jsonObject1 = (JSONObject) o;
                        securityBeans.add(getSecurityBean(jsonObject1));
                    }
                }

                //作业内容各个作业证取名不一样，无法添加
            }
            bean.setMarkerPostion(JSON.toJSONString(markerPosition));
            bean.setJobPersonJson(JSON.toJSONString(jobPersonJson));
            bean.setSecurityJson(JSON.toJSONString(securityBeans));
        }
        return bean;
    }

    private String covertWorkType(String bizName) {
        if (bizName == null) {
            return "";
        } else if (bizName.contains("动火")) {
            return "动火作业";
        } else if (bizName.contains("断路")) {
            return "断路作业";
        } else if (bizName.contains("临时用电")) {
            return "临时用电作业";
        } else if (bizName.contains("高处")) {
            return "高处作业";
        } else if (bizName.contains("受限空间")) {
            return "受限空间作业";
        } else if (bizName.contains("吊装")) {
            return "吊装作业";
        } else if (bizName.contains("盲板抽堵")) {
            return "盲板抽堵作业";
        } else if (bizName.contains("动土")) {
            return "动土作业";
        }
        return "";
    }

    private WorkRailAlarmSecurityBean getSecurityBean(JSONObject jsonObject1) {
        WorkRailAlarmSecurityBean bean = new WorkRailAlarmSecurityBean();
        bean.setSecurityMeasures(jsonObject1.getString("安全措施"));
        JSONArray userIdJson = jsonObject1.getJSONArray("确认人id");
        if (userIdJson != null && userIdJson.size() > 0) {
            for (int i = 0; i < userIdJson.size(); i++) {
                //目前措施确认人只有一个
                JSONObject object = userIdJson.getJSONObject(0);
                Long userId = object.getLong("id");
                if (userId != null) {
                    WorkRailAlarmUserBean userBean = new WorkRailAlarmUserBean();
                    baseUserDao.findById(userId).ifPresent(r -> {
                        userBean.setUniqueId(r.getUniqueId().toString());
                        userBean.setName(r.getRealName());
                    });
                    bean.setEnsurePerson(userBean);
                }
            }
        }
        return bean;
    }

    private List<WorkRailAlarmUserBean> getAlarmUserBean(JSONObject jsonObject1, JSONObject objectIdObject) {
        List<WorkRailAlarmUserBean> list = Lists.newArrayList();
        String userKey = jsonObject1.getString("key");
        JSONArray jsonArray = objectIdObject.getJSONArray(userKey);
        if (jsonArray != null) {
            //需要加入承包商作业人员
            for (Object o : jsonArray) {
                WorkRailAlarmUserBean userBean = new WorkRailAlarmUserBean();
                int flag = 0;
                Long userId;
                try {
                    JSONObject jsonObject = (JSONObject) o;
                    userId = jsonObject.getLong("id");
                    flag = jsonObject.getInteger("flag");
                } catch (Exception e) {
                    userId = Long.valueOf(o.toString());
                }
                if (flag == 0) {
                    baseUserDao.findById(userId).ifPresent(r -> {
                        userBean.setUniqueId(r.getUniqueId() == null ? null : r.getUniqueId().toString());
                        userBean.setName(r.getRealName());
                    });
                } else {
                    contractorStaffDao.findById(userId).ifPresent(r -> {
                        userBean.setUniqueId(r.getUniqueId() == null ? null : r.getUniqueId().toString());
                        userBean.setName(r.getName());
                    });
                }
                list.add(userBean);
            }
//            userBean.setUniqueId("1338442047400710144");
//            userBean.setName("汤姆猫");
        }
        return list;
    }

    private WorkRailAlarmMarkerBean getAlarmMarkerBean(JSONObject jsonObject, String floorId) {
        WorkRailAlarmMarkerBean bean = new WorkRailAlarmMarkerBean();
        bean.setLng(jsonObject.getDouble("x"));
        bean.setLat(jsonObject.getDouble("y"));
        //todo 高度和室内外取前端传值
        Double z = jsonObject.getDouble("z");
        bean.setHeight(z != null ? z : 3d);
        //默认1楼
        String floorNo = "Floor" + 1;
        if (StringUtils.isNotBlank(jsonObject.getString("floorId"))) {
            if (Integer.valueOf(jsonObject.getString("floorId")) < 0) {
                floorNo = "FB" + jsonObject.getString("floorId");
            } else {
                floorNo = "Floor" + jsonObject.getString("floorId");
            }
        } else {
            if (StringUtils.isNotBlank(floorId)) {
                Integer f = Integer.valueOf(floorId);
                if (f < 0) {
                    floorNo = "FB" + floorId;
                } else {
                    floorNo = "Floor" + floorId;
                }
            }
        }
        bean.setFloorNo(floorNo);
        //默认室外
        bean.setInOrOutSide("out");
        if (jsonObject.getString("inOrOutSide") != null) {
            bean.setInOrOutSide(jsonObject.getString("inOrOutSide"));
        }
        return bean;
    }


    private WorkFlowTask newChildTask(WorkFlowTask bizTask, CountersignBean bean) {
        WorkFlowTask childTask = new WorkFlowTask();
        BeanUtils.copyProperties(bizTask, childTask, "id");
        childTask.setAssignKey(bean.getAssignKey());
        childTask.setAssignValue(bean.getAssignValue());
        childTask.setParentId(bizTask.getId());
        return childTask;
    }

    /**
     * 当前节点是否有flowKey
     */
    private Pair<Boolean, String> hasFlowKey(WorkFlowTaskNameBean taskNameBean, WorkFlowExecuteTaskBean taskBean) {
        if (taskNameBean != null && taskNameBean.getFlowKey() != null && !"".equals(taskNameBean.getFlowKey().getKey())) {
            String formData = taskBean.getFormData();
            if (StringUtils.isNotEmpty(formData)) {
                JSONObject jsonObject = JSONObject.parseObject(formData);
                String flowKey = jsonObject.getString(taskNameBean.getFlowKey().getKey());
                if (!org.springframework.util.StringUtils.isEmpty(flowKey)) {
                    return new Pair<>(true, flowKey);
                }
            }
        }
        return new Pair<>(false, null);
    }

    /**
     * 完成父任务并删除子任务
     */
    private void finishTaskAndRemoveChildTask(Task actTask, Map<String, Object> varMap, List<WorkFlowTask> childTaskList) {
        taskService.complete(actTask.getId(), varMap);
        //删除子任务
        if (!CollectionUtils.isEmpty(childTaskList)) {
            workFlowTaskDao.deleteInBatch(childTaskList);
        }
    }

    /**
     * 获取当前任务节点信息
     *
     * @param id
     * @return
     */
    @Override
    public ResultBean getTaskById(Long id) {
        WorkFlowExecuteTaskBean bean = new WorkFlowExecuteTaskBean();
        Optional<WorkFlowTask> owf = workFlowTaskDao.findById(id);
        if (owf.isPresent()) {
            BeanUtils.copyProperties(owf.get(), bean);
            bean.setWorkFlowProcessId(owf.get().getProcessId());
        } else {
            throw new IllegalArgumentException("该数据已被删除");
        }
        return ResultBean.success(bean);
    }

    /**
     * 获取关联作业信息根据taskCode
     *
     * @param taskCode
     * @return
     */
    @Override
    public RelatedTaskInfoVO getRelatedTaskByCode(String taskCode) throws ApiBusinessException {
        RelatedTaskInfoVO infoVO = new RelatedTaskInfoVO();
        Optional<WorkFlowTask> optionalTask = workFlowTaskDao.findOneByCodeAndParentId(taskCode, 0L);
        if (optionalTask.isPresent()) {
            WorkFlowTask task = optionalTask.get();
            infoVO.setFormData(task.getFormData());
            Optional<WorkFlowProcess> optionalProcess = workFlowProcessService.findById(task.getProcessId());
            optionalProcess.ifPresent(workFlowProcess -> infoVO.setFormJson(workFlowProcess.getFormJson()));
        } else {
            throw new ApiBusinessException(Status.CUR_TASK_HAS_BEEN_DELETED);
        }
        return infoVO;
    }

    /**
     * 删除任务节点
     * flag 0 作废; 1 删除
     *
     * @param id
     */

    @Override
    public void deleteTask(Long id, Integer flag, String comments) {
        WorkFlowTask task = workFlowTaskDao.findById(id).get();
        WorkFlowTask childTask = task;

        //草稿作废直接删除
        if (flag == 0 && WorkFlowStatusEnum.DRAFT.getValue().equals(task.getStatus())) {
            flag = 1;
        }

        String curNodeTaskName = task.getTaskName();
        //作业作废，需要删除作业区域
        //railAlarm(task.getTaskName(), task, task.getFormData(), 1);
        railAlarmDelete(task);

        //作业作废，需要将风险区域等级降低
        WorkFlowProcess process = processDao.findById(task.getProcessId()).get();
        Pair<List<String>, String> pair = getRiskAssessment(process.getFormJson());
        List<String> nodeList = pair.getKey();
        String riskAssessmentKey = pair.getValue();
        boolean riskLevelNeedChange = !CollectionUtils.isEmpty(nodeList);
        if (riskLevelNeedChange) {
            JSONObject formObject = JSONObject.parseObject(task.getFormData());
            JSONObject riskObject = formObject.getJSONObject(riskAssessmentKey);
            if (riskObject == null) {
                log.info("作业票风险评估，流程流经作废，formData中无风险评估信息, riskKey:{}", riskAssessmentKey);
            } else {
                Long riskPointId = riskObject.getLong("riskPointId");
                Long riskDistrictId = riskObject.getLong("riskDistrictId");
                Long riskEvaluationId = riskObject.getLong("riskEvaluationId");
                if (riskPointId != null && riskDistrictId != null) {
                    riskEvaluationBusinessService.changeDistrictLevelFromLibraryPoint(riskEvaluationId, riskDistrictId, 0, task.getCode());
                    log.info("作业票风险评估，流程流经作废,风险等级降低 success");
                }
            }
        }
        //场景：多人验收时，某个人发现验收不合格可以终止任务(即任务走到结束节点)
        Long parentId = task.getParentId();
        List<WorkFlowTaskNameBean> taskNameList = workFlowProcessService.findTaskNameList(task.getProcessId());
        WorkFlowTaskNameBean endTask = taskNameList.stream().filter(item -> item.getCompleteStatus() == 1).collect(Collectors.toList()).get(0);
        if (parentId != null && parentId != 0) {
            Optional<WorkFlowTask> optional = workFlowTaskDao.findById(parentId);
            if (optional.isPresent()) {
                task = optional.get();
            }
            //删除子任务
            List<WorkFlowTask> childList = workFlowTaskDao.findByParentId(parentId);
            workFlowTaskDao.deleteInBatch(childList);
        }

        if (flag == 0) {
            String formData = task.getFormData();
            //汇总查询的时候需要任务的 对象信息  --作废的任务其实都可以看到
            if (parentId != null && parentId != 0) {
                formData = childTask.getFormData();
            }
            if (!org.springframework.util.StringUtils.isEmpty(formData)) {
                JSONObject jsonObject = JSONObject.parseObject(formData);
                jsonObject.put("action", "作废");
                formData = jsonObject.toJSONString();
            }
            //是否保存历史记录
            Map<String, WorkFlowTaskNameBean> taskMap = taskNameList.stream().collect(Collectors.toMap(r -> r.getTaskName(), r -> r, (r, v) -> r));
            WorkFlowTaskNameBean taskNameBean = taskMap.get(task.getTaskName());
            if (taskNameBean != null && "1".equals(taskNameBean.getRecordHistory())) {
                checkSaveTaskHistory(task.getTaskName(), task.getId(), formData, taskNameBean);
            }

            //主任务置位
            task.setStatus(1);
            task.setTaskName(endTask.getTaskName());
            task.setAssignKey(null);
            task.setAssignValue(null);

            //如果编码为空，设置业务编码
            String taskCode = StringUtils.isEmpty(task.getCode()) ? this.generateTaskCode(process) : task.getCode();
            task.setCode(taskCode);
            //设置编号与状态固定字段
            task.setFormData(addStatus4FormData(task.getFormData(), null, task.getTaskName(), task, taskNameList, taskCode, task.getExceptionStatus()));
            //前端需要显示作废状态
            String formData1 = task.getFormData();
            if (!org.springframework.util.StringUtils.isEmpty(formData1)) {
                JSONObject jsonObject = JSONObject.parseObject(formData1);
                jsonObject.put(WorkFlowConstants.WORK_FLOW_TASK_STATUS_KEY, "作废");
                task.setState("作废");
                formData1 = jsonObject.toJSONString();
            }
            task.setFormData(formData1);
            if (StringUtils.isNotBlank(comments)) {
                task.setComments(comments);
            }
            workFlowTaskDao.save(task);

            //保存流程流转历史记录
            insertTaskAssignHistory(curNodeTaskName, Long.valueOf(task.getTaskId()), WorkFlowOperationEnum.BECOME_INVALID.getValue(), null, null, null, taskCode, null);
        }

        //删除业务数据
        if (flag == 1) {
            workFlowTaskDao.delete(task);
            //taskService.deleteTask(task.getTaskId());
        }
        //删除动态风险记录
        if (process.getBizTypeName().equals("作业票")) {
            workFlowTaskDynamicService.batchDeletaDynamicRecordsByTaskCode(task.getCode());
        }
        // 隐患治理删除/作废，风险等级重新评估
        if (WorkFlowTaskRefSource.YHPC.getSource().equals(task.getRefSource())) {
            investigateRecordService.changePlanInvalid(task.getRefDetailId(), "deleteTask");
        }
        //删除流程节点
        try {
            //草稿状态未开始流程
            if (!WorkFlowStatusEnum.DRAFT.getValue().equals(task.getStatus())) {
                runtimeService.deleteProcessInstance(task.getProcessInstanceId(), "用户删除节点：" + task.getTaskName());
            }
        } catch (Exception e) {
            log.error("用户删除节点异常：", e);
        }
        //删除未发送的通知提醒
        noticeWaitingTriggerListService.deleteNotTriggered(task.getCode());
        // 大屏作业票图标刷新
        bigScreenRefresh(task.getBizName());
    }


    /**
     * 保存任务节点
     *
     * @param taskBean
     */
    @Override
    public Long saveTask(WorkFlowExecuteTaskBean taskBean, boolean typeFlag) throws ApiBusinessException, IOException {
        log.info("saveTask--------------->> 参数: {}", JSON.toJSONString(taskBean));
        WorkFlowTask entity = new WorkFlowTask();
        if (taskBean.getId() != null) {
            Optional<WorkFlowTask> optional = workFlowTaskDao.findById(taskBean.getId());
            if (optional.isPresent()) {
                entity = optional.get();
                if (StringUtils.isNotBlank(entity.getTaskId()) && !entity.getTaskId().equals(taskBean.getTaskId())) {
                    throw new ApiBusinessException(Status.PROCESS_HAS_BEEN_PROCESSED);
                }
            }
        } else {
            //草稿状态
            entity.setStatus(WorkFlowStatusEnum.DRAFT.getValue());
            entity.setProcessId(taskBean.getWorkFlowProcessId());
        }
        entity.setVarMapData(taskBean.getVarMap() == null ? "" : taskBean.getVarMap().toString());
        entity.setObjectId(taskBean.getObjectId());

        //作业修改，调风险等级change
        WorkFlowProcess process = processDao.findById(entity.getProcessId()).get();
        Pair<List<String>, String> pair = getRiskAssessment(process.getFormJson());
        List<String> nodeList = pair.getKey();
        String riskAssessmentKey = pair.getValue();
        boolean riskLevelNeedChange = !CollectionUtils.isEmpty(nodeList);
        if (riskLevelNeedChange) {
            JSONObject formObject = JSONObject.parseObject(entity.getFormData());
            //草稿 formObject
            if (formObject != null) {
                JSONObject riskObject = formObject.getJSONObject(riskAssessmentKey);
                if (riskObject == null) {
                    log.info("作业票风险评估，流程流经修改，formData中无风险评估信息, riskKey:{}", riskAssessmentKey);
                } else {
                    Long riskPointId = riskObject.getLong("riskPointId");
                    Long riskDistrictId = riskObject.getLong("riskDistrictId");
                    Long riskEvaluationId = riskObject.getLong("riskEvaluationId");
                    if (riskPointId != null && riskDistrictId != null) {
                        int flag = nodeList.contains(entity.getPreTaskName()) ? 1 : 0;
                        riskEvaluationBusinessService.changeDistrictLevelFromLibraryPoint(riskEvaluationId, riskDistrictId,
                                flag, entity.getCode());
                        log.info("作业票风险评估，流程流经修改,风险等级{} success", flag == 1 ? "升高" : "降低");
                    }
                }
            }
        }
        //如果编码为空，设置业务编码
        String taskCode = StringUtils.isEmpty(entity.getCode()) ? this.generateTaskCode(process) : entity.getCode();
        entity.setCode(taskCode);
        //签字异常,整个流转过程存在一次即异常，后期可将异常拆出来作为独立模块
        if (WorkFlowExceptionStatusEnum.SIGN.getValue().equals(taskBean.getExceptionStatus())) {
            entity.setExceptionStatus(taskBean.getExceptionStatus());
        }
        //typeId前端只在第一次传..
        if (taskBean.getTypeId() != null) {
            entity.setTypeId(taskBean.getTypeId());
        }
        //设置到form_data
        String formData = taskBean.getFormData();
        if (StringUtils.isNotEmpty(formData)) {
            JSONObject jsonObject = JSONObject.parseObject(formData);
            jsonObject.put(WorkFlowConstants.WORK_FLOW_TASK_ID_KEY, taskCode);
            //添加异常类型
            //添加签字异常类型
            if (WorkFlowExceptionStatusEnum.SIGN.getValue().equals(entity.getExceptionStatus())) {
                jsonObject.put(WorkFlowConstants.WORK_FLOW_EXCEPTION_STATUS, WorkFlowExceptionStatusEnum.SIGN.getDesc());
            }
            entity.setFormData(jsonObject.toJSONString());
        }

        //抽取数据权限字段值
        processDataAuth(entity, taskBean, process);

        //防止会签/或签任务被随意改动, 修改的操作一般只存在于非审批节点，正常情况下不会出现。
        if (entity.getParentId() != null && entity.getParentId() != 0) {
            WorkFlowTask task = workFlowTaskDao.save(entity);
            return task.getId();
        }

        //获取下一个节点指定人员/部门
        String taskName = entity.getTaskName();
        WorkFlowTaskNameBean taskConfig = this.getCurTaskConfig(taskBean.getWorkFlowProcessId(), taskName);
        //动态风险
        if (process.getBizTypeName().equals("作业票") && typeFlag) {
            workFlowTaskDynamicService.saveDynamicRecords(process.getId(), process.getFormJson(), entity.getCode(), entity.getPreTaskName(), taskBean.getFormData(), taskConfig != null && StringUtils.isNotBlank(taskConfig.getNextTaskName()));
        }
        List<CountersignBean> countersignList = this.getAssignMap(taskName, taskBean.getObjectId(), taskBean.getVarMap(), taskBean.getId(), taskConfig);
        CountersignBean countersignBean = countersignList.get(0);
        entity.setAssignKey(countersignBean.getAssignKey());
        entity.setAssignValue(countersignBean.getAssignValue());

        WorkFlowTask workFlowTask = workFlowTaskDao.save(entity);
        //草稿按钮权限需要根据节点获取
        if (WorkFlowStatusEnum.DRAFT.getValue().equals(workFlowTask.getStatus())) {
            List<String> taskList = processAPI.userTaskList(process.getModelId());
            if (CollectionUtils.isNotEmpty(taskList) && StringUtils.isNotEmpty(formData)) {
                String firstTaskName = taskList.get(0);
                formData = workFlowTask.getFormData();
                JSONObject jsonObject = JSONObject.parseObject(formData);
                jsonObject.put(WorkFlowConstants.WORK_FLOW_TASK_NAME, firstTaskName);

                workFlowTask.setFormData(jsonObject.toJSONString());
                workFlowTask.setTaskName(firstTaskName);
                workFlowTask = workFlowTaskDao.save(workFlowTask);
            }
        } else {
            //分析提醒
            processNoticeListService.generateNotice(workFlowTask.getProcessId(), workFlowTask.getCode(), process.getBizName(), workFlowTask.getFormData(), workFlowTask.getObjectId());
        }
        return workFlowTask.getId();
    }


    @Scheduled(initialDelay = 10000, fixedDelay = 5000)
    public void scan() {
        processDynamicRecords();
    }

    @Override
    public void processDynamicRecords() {
        List<BpEnterpriseInfo> all = AlertListenerConfig.getAlertConfig().getBpEnterpriseInfoDao().findAll();
        for (BpEnterpriseInfo info : all) {
            String key = getRedisDynamicKey(info.getOrgCode(), info.getTenentId());
            RList<String> list = redisClient.getList(key);
            if (CollectionUtils.isEmpty(list)) {
                continue;
            }
            workFlowTaskDynamicService.processDynamicRecords(list, info.getOrgCode(), info.getTenentId());
        }
    }


    private String getRedisDynamicKey(String companyCode, Long tenentId) {
        return companyCode + ":" + tenentId + ":" + "dynTask";
    }


    /**
     * 暂存
     *
     * @param taskBean
     */
    @Override
    public Long tempSaveTask(WorkFlowExecuteTaskBean taskBean) throws ApiBusinessException, IOException {
        log.info("tempSaveTask--------------->> 参数: {}", JSON.toJSONString(taskBean));
        if (taskBean.getId() != null) {
            Optional<WorkFlowTask> optional = workFlowTaskDao.findById(taskBean.getId());
            if (optional.isPresent()) {
                WorkFlowTask entity = optional.get();
                if (WorkFlowStatusEnum.COMPLETED.getValue().equals(entity.getStatus())) {
                    throw new ApiBusinessException(Status.PROCESS_HAS_BEEN_PROCESSED);
                }
            }
        }
        return saveTask(taskBean, false);
    }


    /**
     * 创建业务流程新任务
     *
     * @param bean
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String createNewTask(WorkFlowTaskCreateBean bean, HttpServletRequest request) throws ApiBusinessException {
        //用户操作类型
        final String operation = StringUtils.isEmpty(bean.getOperation()) ? WorkFlowOperationEnum.APPLY.getValue() : bean.getOperation();
        WorkFlowTask bizTask = new WorkFlowTask();
        bizTask.setProcessId(bean.getWorkFlowId());
        final String taskName = bean.getTaskName();
        bizTask.setTaskName(taskName);
        bizTask.setVarMapData(bean.getVarMap() == null ? "" : bean.getVarMap().toString());
        bizTask.setStatus(0);
        bizTask.setObjectId(bean.getObjectId());
        bizTask = workFlowTaskDao.save(bizTask);
        String refSource = bean.getRefSource();
        Long refDetailId = bean.getRefDetailId();
        final Long bizTaskId = bizTask.getId();
        if (refSource != null) {
            Assert.isTrue(WorkFlowTaskRefSource.hasSource(refSource), "不支持此模块");
            //隐患排查关联流程任务数据id
            if (refDetailId != null && refSource.equals(WorkFlowTaskRefSource.YHPC.getSource())) {
                boolean isHistory = false;
                // 今日表不存在，则取历史表
                BpInvestigateRecordItem recordItem = bpInvestigateRecordItemDao.findById(refDetailId).orElse(null);
                if (null == recordItem) {
                    isHistory = true;
                    recordItem = investigateHistoryMapper.getHistoryItemById(refDetailId);
                }
                recordItem.setWorkFlowTaskId(bizTaskId);
                if (isHistory) {
                    investigateHistoryMapper.updateRecordItemRef(recordItem);
                } else {
                    bpInvestigateRecordItemDao.save(recordItem);
                }
            } else if (refDetailId != null && refSource.equals(WorkFlowTaskRefSource.ZNXJ.getSource())) {
                //智能巡检关联流程任务数据id
                PatrolRecordItem patrolRecordItem = patrolRecordItemService.getById(refDetailId);
                if (patrolRecordItem == null) {
                    throw new IllegalArgumentException("此详情数据不存在");
                }
                patrolRecordItem.setWorkflowTaskId(bizTaskId);
                patrolRecordItemService.saveOrUpdate(patrolRecordItem);
            } else if (refDetailId != null && refSource.equals(WorkFlowTaskRefSource.AQBBZRZ.getSource())) {
                MhMajorHazardTaskRecordItem recordItem = mhMajorHazardTaskRecordItemService.getById(refDetailId);
                if (recordItem == null) {
                    throw new IllegalArgumentException("此详情数据不存在");
                }
                recordItem.setWorkFlowTaskId(bizTaskId);
                recordItem.setNodeFlag(0);
                mhMajorHazardTaskRecordItemService.saveOrUpdate(recordItem);

                MhMajorHazardTaskRecord record = mhMajorHazardTaskRecordService.getById(recordItem.getRecordId());
                if (record == null) {
                    throw new IllegalArgumentException("此详情数据不存在");
                }
                List<MhMajorHazardTaskRecordItem> recordIdByItem = mhMajorHazardTaskRecordMapper.findByRecordIdByItem(record.getId());
                Integer excepHandle = 2;
                for (MhMajorHazardTaskRecordItem records : recordIdByItem) {
                    if (records.getResult() == 0 && records.getWorkFlowTaskId() == null) {
                        excepHandle = 0;
                    }
                }
                record.setExcepHandle(excepHandle);
                mhMajorHazardTaskRecordService.saveOrUpdate(record);
            }
        }
        bizTask.setRefId(bean.getRefId());
        bizTask.setRefSource(refSource);
        bizTask.setRefDetailId(refDetailId);
        bizTask = workFlowTaskDao.save(bizTask);


        List<WorkFlowTaskNameBean> taskNameList = workFlowProcessService.findTaskNameList(bean.getWorkFlowId());

        WorkFlowProcess process = workFlowProcessService.findById(bean.getWorkFlowId()).get();

        //如果编码为空，设置业务编码
        String taskCode = StringUtils.isEmpty(bizTask.getCode()) ? this.generateTaskCode(process) : bizTask.getCode();
        bizTask.setCode(taskCode);
        //签字异常,整个流转过程存在一次即异常，后期可将异常拆出来作为独立模块
        if (WorkFlowExceptionStatusEnum.SIGN.getValue().equals(bean.getExceptionStatus())) {
            bizTask.setExceptionStatus(bean.getExceptionStatus());
        }

        // 检查是否保存历史记录
        checkTaskExecute(taskName, bizTaskId, bean.getFormData(), taskNameList, process.getFormKeyLabelJson());

        ProcessInstance instance = runtimeService.startProcessInstanceByKey(process.getDefinitionKey(), String.valueOf(bizTaskId), bean.getVarMap());
        log.info("创建业务流程实例 byID: " + instance.getId() + ", 业务流程：" + process.getBizName());

        if (process.getTaskNameList() == null || process.getTaskNameList().isEmpty()) {
            log.warn("业务流程还未配置流程节点， 无法启动节点:" + taskName);
            return null;
        }

        List<WorkFlowTaskNameBean> taskList = taskNameList.stream().filter(item -> item.getTaskName().equals(taskName)).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(taskList)) {
            log.warn("业务流程还未配置流程节点， 无法启动节点:" + taskName);
            return null;
        }
        String targetElementId = taskList.get(0).getTaskElementId();
        //3. 执行当前节点
        Task actTask = taskService.createTaskQuery().processInstanceId(instance.getId()).processInstanceBusinessKey(String.valueOf(bizTaskId)).singleResult();

        //设置业务逻辑任务ID
        bean.getVarMap().put("bizId", bizTaskId);
        JumpTaskCommand jumpTaskCommand = new JumpTaskCommand(actTask.getId(), targetElementId, bean.getVarMap());
        managementService.executeCommand(jumpTaskCommand);


        //调用API接口， 同步隐患登记
        hiddenDangerSender.addHiddenDanger(bean.getFormData(), actTask.getName(), process.getFormKeyLabelJson(), request);

        //查询当前新节点task Id , 保存至 业务表
        Task newTask = taskService.createTaskQuery().processInstanceId(instance.getId()).processInstanceBusinessKey(String.valueOf(bizTaskId)).singleResult();
        if (newTask != null) {
            bizTask.setTaskId(newTask.getId());
            bizTask.setProcessInstanceId(newTask.getProcessInstanceId());
        } else {
            bizTask.setStatus(WorkFlowStatusEnum.COMPLETED.getValue());
        }
        //获取下一个节点指定人员/部门
        WorkFlowTaskNameBean taskConfig = this.getCurTaskConfig(bean.getWorkFlowId(), taskName);
        Integer countersign = null;
        if (taskConfig != null) {
            countersign = taskConfig.getCountersign();
        }
        List<CountersignBean> countersignList = this.getAssignMap(taskName, bean.getObjectId(), bean.getVarMap(), bizTaskId, taskConfig);
        WorkFlowTaskNameBean taskNameBean = taskNameList.stream().filter(item -> item.getTaskName().equals(taskName)).collect(Collectors.toList()).get(0);
        WorkFlowParticipantRuleEnum participantRule = WorkFlowParticipantRuleEnum.find(countersign);
        switch (participantRule) {
            case EVERYONE:
            case ONE_OF:
                //保存子任务
                for (CountersignBean countersignBean : countersignList) {
                    WorkFlowTask childTask = newChildTask(bizTask, countersignBean);
                    childTask.setFormData(addStatus4FormData(bean.getFormData(), actTask.getName(), childTask.getTaskName(), childTask, taskNameList, taskCode, bean.getExceptionStatus()));
                    workFlowTaskDao.save(childTask);
                }
                bizTask.setFormData(addStatus4FormData(bean.getFormData(), taskNameBean.getPreTaskName(), taskNameBean.getTaskName(), bizTask, taskNameList, taskCode, bean.getExceptionStatus()));
                //1.父任务设置assign_value -1 避免查询
                bizTask.setAssignKey(WorkFlowAssignKey.PERSON.getCode());
                bizTask.setAssignValue(String.valueOf(-1));
                bizTask.setPreTaskName(taskNameBean.getPreTaskName());
                bizTask.setAppStatus(bean.getAppStatus());
                workFlowTaskDao.save(bizTask);
                break;
            default:
                CountersignBean countersignBean = countersignList.get(0);
                bizTask.setAssignKey(countersignBean.getAssignKey());
                bizTask.setAssignValue(countersignBean.getAssignValue());
                //设置编号与状态固定字段
                bizTask.setFormData(addStatus4FormData(bean.getFormData(), taskNameBean.getPreTaskName(), taskNameBean.getTaskName(), bizTask, taskNameList, taskCode, bean.getExceptionStatus()));
                bizTask.setPreTaskName(actTask.getName());
                bizTask.setAppStatus(bean.getAppStatus());
                workFlowTaskDao.save(bizTask);
        }
        if (Constant.SYNC_ON == process.getSyncStatusOnOff()) {
            workFlowTaskProcessListService.saveStatisticData(bizTask.getId(), bizTask.getProcessId(), bizTask.getCode(), bizTask.getFormData(), bizTask.getAuthType(), bizTask.getAuthValue(), Context.getCurrentTenantId(), Context.getCompanyCode());
        }
        //保存流程流转历史记录
        saveTaskAssignHistoryByCountersignType(actTask.getName(), newTask != null ? Long.valueOf(newTask.getId()) : null, operation, countersignList, countersign, newTask != null ? newTask.getName() : null, taskCode, null);
        //推送待办信息
        pushToDoMsg(countersignList, bizTask.getAuthType(), bizTask.getAuthValue(), newTask != null ? newTask.getName() : null, bizTask.getCode(), bizTaskId, process.getBizName());
        // 大屏作业票刷新
        bigScreenRefresh(bizTask.getBizName());
        // 隐患治理完成时恢复计划状态
        if (WorkFlowTaskRefSource.YHPC.getSource().equals(bizTask.getRefSource())) {
            BpInvestigateRecord record = investigateRecordRepository.findByItemId(bizTask.getRefDetailId());
            // 今日表里没有，查历史表
            if (null == record) {
                record = investigateHistoryMapper.findRecordByItemId(bizTask.getRefDetailId());
            }
            if (null != record) {
                // 来自风险分级管控的排查记录才调用此方法
                if (record.getSourceType() == 1) {
                    investigateRecordService.repairV2(bizTask.getRefDetailId());
                    if (taskConfig == null || StringUtils.isBlank(taskConfig.getNextTaskName())) {
                        investigateRecordService.changePlanInvalid(bizTask.getRefDetailId(), "createNewTask");
                    }
                }
            }
        } else if (WorkFlowTaskRefSource.ZNXJ.getSource().equals(bizTask.getRefSource())) {
            // 智能巡检
            patrolRecordItemService.repair(bizTask.getRefDetailId());
            // 无下一节点时，直接处理完成
            if (taskConfig == null || StringUtils.isBlank(taskConfig.getNextTaskName())) {
                patrolRecordItemService.repairFinish(bizTask.getRefDetailId());
            }
        }
        return newTask != null ? newTask.getId() : null;
    }


    private void checkTaskExecute(String taskName, Long taskId, String formData, List<WorkFlowTaskNameBean> taskNameList, String formKeyLabelJson) {
        //获取当前节点配置信息
        if (taskNameList != null && !taskNameList.isEmpty()) {
            List<WorkFlowTaskNameBean> subList = taskNameList.stream().filter(item -> item.getTaskName().equalsIgnoreCase(taskName)).collect(Collectors.toList());
            if (subList == null || subList.isEmpty()) {
                return;
            }
            WorkFlowTaskNameBean taskNameBean = subList.get(0);
            //判断是否保存历史记录
            checkSaveTaskHistory(taskName, taskId, formData, taskNameBean);
            //是否风险复评
            checkRiskReEval(taskName, taskId, formData, taskNameBean, formKeyLabelJson);
        }
    }

    /**
     * 风险复评
     *
     * @param taskName
     * @param taskId
     * @param formData
     * @param taskNameBean
     */
    private void checkRiskReEval(String taskName, Long taskId, String formData, WorkFlowTaskNameBean taskNameBean, String formKeyLabelJson) {
        if (StringUtils.isEmpty(taskNameBean.getRiskreeval())) {
            return;
        }
        JSONObject formDataObj = JSON.parseObject(formData);
        JSONObject formLabelObj = JSON.parseObject(formKeyLabelJson);
        // 根据配置风险区域表单字段名称取出对应 key
        String key = formLabelObj.getString(taskNameBean.getRiskreeval());
        if (key == null) {
            return;
        }
        String riskDistName = formDataObj.getString(key);
        if (StringUtils.isNotEmpty(riskDistName)) {
            RiskDistrict riskDistrict = riskDistrictDao.findFirstByName(riskDistName);
            // 触发风险区域复评计划
            if (riskDistrict != null) {
                riskEvaluationPlanService.batchSendEvaluationRemind(riskDistrict.getId(), riskDistrict.getName(), 1);
            }
        }

    }

    /**
     * 保存历史记录
     *
     * @param taskName
     * @param taskId
     * @param formData
     * @param taskNameBean
     */

    private void checkSaveTaskHistory(String taskName, Long taskId, String formData, WorkFlowTaskNameBean taskNameBean) {
        if (taskNameBean.getRecordHistory() == null || "0".equals(taskNameBean.getRecordHistory())) {
            return;
        }
        WorkFlowTaskHistory history = new WorkFlowTaskHistory();
        WorkFlowTask workFlowTask = workFlowTaskDao.findById(taskId).get();
        Long parentId = workFlowTask.getParentId();
        if (parentId != null && parentId != 0) {
            workFlowTaskDao.findById(parentId).ifPresent(r -> history.setParentId(r.getId()));
        } else {
            history.setParentId(taskId);
        }

        history.setTaskName(taskName);
        history.setFormData(formData);
        WorkFlowTaskHistory last = workFlowTaskHistoryDao.findFirstByParentIdOrderByIdDesc(taskId);
        if (last == null) {
            history.setVersion(1);
        } else {
            history.setVersion((last.getVersion() == null ? 1 : last.getVersion()) + 1);
        }
        workFlowTaskHistoryDao.save(history);

    }


    @Override
    public ResultBean findTaskList(WorkFlowTaskQueryBean queryBean, Pageable pageable) {
        Long currentUser = Context.getCurrentUser().getRealUserId();
        Long departId = Context.getCurrentDepartId();
        Long jobId = Context.getJobId();
        List<Long> roleIds = Context.getRoleIds();
        Integer invokeFlag = queryBean.getInvokeFlag();

        StringBuffer querySql = new StringBuffer(" select *  from wwyt_workflow_task where 1=1 ");
        StringBuffer countSql = new StringBuffer(" select count(*) from wwyt_workflow_task where 1=1 ");

        // 拼接节点列表
        StringBuffer taskNameIn = new StringBuffer("");
        for (String tName : queryBean.getTaskName()) {
            taskNameIn.append("'").append(tName).append("' ,");
        }
        //去除最后一个 ,
        if (queryBean.getTaskName().size() != 0) {
            taskNameIn.deleteCharAt(taskNameIn.length() - 1);
        }

        //拼接角色列表
        StringBuffer roleIdIn = new StringBuffer("");
        if (roleIds != null && !roleIds.isEmpty()) {
            for (Long tRoleId : roleIds) {
                roleIdIn.append(tRoleId).append(",");
            }
            //去除最后一个 ,
            roleIdIn.deleteCharAt(roleIdIn.length() - 1);
        } else {
            roleIdIn.append("-1");
        }

        StringBuffer whereSql = new StringBuffer();
        whereSql.append(" and process_id=").append(queryBean.getWorkFlowProcessId());

        String taskName = taskNameIn.toString();
        if (!StringUtils.isEmpty(taskName)) {
            whereSql.append(" and task_name in (").append(taskNameIn.toString()).append(")  ");
        }

        if (queryBean.getIsAssignUser() == null || queryBean.getIsAssignUser() == 0) {
            whereSql.append(" and ( case when assign_key is null then  assign_value is null  ")
                    .append("            when assign_key='person' then  assign_value ='").append(currentUser).append("'  ")
                    .append("            when assign_key='department' then  assign_value = '").append(departId).append("'  ")
                    .append("            when assign_key='job' then  assign_value = '").append(jobId).append("'  ")
                    .append("            when assign_key='role' then  assign_value in (").append(roleIdIn).append(")  ")
                    .append("            when assign_key='post' then  assign_value in (").append(jobId).append(")  ");
            if (invokeFlag == 0) {
                whereSql.append("            when assign_value = '-1' then  assign_key ='-1' ");  //过滤掉主任务
            }
            whereSql.append("      end ) ");
        } else if (queryBean.getIsAssignUser() == 1) {
            if (invokeFlag == 0) {
                whereSql.append(" and (assign_value != '-1' or assign_value is null) ");  //过滤掉主任务
            }
        }
        whereSql.append(" and delete_flag ='0' ");
        //大屏查询只保留主任务
        if (invokeFlag == 1) {
            whereSql.append(" and parent_id = 0 ");
        }
        if (queryBean.getTypeId() != null && queryBean.getTypeId() != 0) {
            whereSql.append(" and type_id=").append(queryBean.getTypeId()).append("  ");
        }

        String searchSql = workFlowTaskProcessListService.buildSearchSql(queryBean.getSearchJson());
        if (StringUtils.isNotEmpty(searchSql)) {
            whereSql.append(searchSql);
        }

        StringBuffer limitSql = new StringBuffer(" order by id desc");
        String totalCount = "0";
        if (pageable != null) {
            limitSql.append(" limit ").append((pageable.getPageNumber() - 1) * pageable.getPageSize()).append(" , ").append(pageable.getPageSize());
            totalCount = entityManager.createNativeQuery(countSql.append(whereSql).toString()).getResultList().get(0).toString();
        }

        List<WorkFlowTask> taskList = entityManager.createNativeQuery(querySql.append(whereSql).append(limitSql).toString(), WorkFlowTask.class).getResultList();

        return ResultBean.pageData(taskList, pageable == null ? taskList.size() : Long.valueOf(totalCount));

    }

    /**
     * Set task code
     * 作业生成时已添加，此功能后期移除
     *
     * @param taskList
     */
    @Deprecated
    @Override
    public void setCode(List<WorkFlowTask> taskList) {
        if (!CollectionUtils.isEmpty(taskList)) {
            List<Long> processIdList = taskList.stream().map(r -> r.getProcessId()).distinct().collect(Collectors.toList());
            Map<Long, String> codeMap = processDao.findAllById(processIdList).stream().filter(r -> r.getCodePrefix() != null)
                    .collect(Collectors.toMap(WorkFlowProcess::getId, WorkFlowProcess::getCodePrefix));
            taskList.forEach(r -> {
                setCodeDetail(codeMap.getOrDefault(r.getProcessId(), ""), r);
            });
        }
    }

    /**
     * 生成任务编号
     *
     * @param codePrefix
     * @return
     */
    public String generateTaskCode(String codePrefix) {
        String dateFormat = SimpleDateFormatCache.getYmd_Pure().format(new Date());
        int i = ThreadLocalRandom.current().nextInt(1, 99999);
        String index = String.format("%05d", i);
        return StringUtils.isEmpty(codePrefix) ? dateFormat + index : codePrefix + dateFormat + index;
    }

    /**
     * 生成任务编号
     *
     * @param process
     * @return
     */
    public String generateTaskCode(WorkFlowProcess process) {
        if (process.getCodeStrategyId() != null) {
            Optional<WorkFlowProcessCodeStrategy> ows = workFlowProcessCodeStrategyDao.findById(process.getCodeStrategyId());
            String code = "";
            if (ows.isPresent()) {
                WorkFlowProcessCodeStrategy strategy = ows.get();
                //编号末尾种子
                Integer seed = strategy.getBizCodeNumber();
                if (seed != null) {
                    if (strategy.getTimestamp() != null && strategy.getTimestamp() != -1 && seed + 1 > 9999) {
                        strategy.setBizCodeNumber(1);
                    } else {
                        strategy.setBizCodeNumber(seed + 1);
                    }
                    workFlowProcessCodeStrategyDao.save(strategy);
                }
                //时间戳
                String timeCode = null;
                if (strategy.getTimestamp() != null && strategy.getTimestamp() != -1) {
                    String value = WorkFlowCodeTimeStampEnum.findValueByIndex(strategy.getTimestamp());
                    if (StringUtils.isNotBlank(value)) {
                        timeCode = new SimpleDateFormat(value).format(new Date());
                    }
                }
                String timeCodeWithSep = timeCode == null ? "" : timeCode + "-";
                String timeCodeWithoutSep = timeCode == null ? "" : timeCode;
                int suffixLen = 4;
                // 没有选日期后缀有8个
                if (strategy.getTimestamp() != null && strategy.getTimestamp() == -1) {
                    suffixLen = 8;
                }
                String suffixFmt = "%0" + suffixLen + "d";
                //编码前缀及分隔符
                if (strategy.getCodePrefix() != null) {
                    if (strategy.getSeparatorFlag() != null && strategy.getSeparatorFlag().equals(1)) {
                        code = strategy.getCodePrefix() + "-" + timeCodeWithSep + String.format(suffixFmt, seed);
                    } else {
                        code = strategy.getCodePrefix() + timeCodeWithoutSep + String.format(suffixFmt, seed);
                    }
                } else {
                    if (strategy.getSeparatorFlag() != null && strategy.getSeparatorFlag().equals(1)) {
                        code = timeCodeWithSep + String.format(suffixFmt, seed);
                    } else {
                        code = timeCodeWithoutSep + String.format(suffixFmt, seed);
                    }
                }
            } else {
                return this.generateTaskCode(process.getCodePrefix());
            }
            return code;
        } else {
            return this.generateTaskCode(process.getCodePrefix());
        }
    }

    /**
     * 设置编号，不存在生成并更新(作业生成时已添加，此功能后期移除)
     */
    @Deprecated
    public String setCodeDetail(String codePrefix, WorkFlowTask task) {
        String code = task.getCode();
        //int needSaveFlag = 0;
        if (task.getCode() == null) {
            String dateFormat = SimpleDateFormatCache.getYmd_Pure().format(task.getCreateTime());
            int i = ThreadLocalRandom.current().nextInt(1, 99999);
            String index = String.format("%05d", i);
            code = codePrefix + dateFormat + index;
            task.setCode(code);
            //needSaveFlag = 1;
        }
        //设置到form_data
        String formData = task.getFormData();
        if (StringUtils.isNotEmpty(formData)) {
            JSONObject jsonObject = JSONObject.parseObject(formData);
            jsonObject.put(WorkFlowConstants.WORK_FLOW_TASK_ID_KEY, code);
            task.setFormData(jsonObject.toJSONString());
        }
        //if (needSaveFlag == 1) {
        workFlowTaskDao.save(task);
        //}
        return code;
    }


    @Override
    public void updateAppStatus(Long id, String status) {
        WorkFlowTask workFlowTask = workFlowTaskDao.findById(id).get();
        workFlowTask.setAppStatus(status);
        workFlowTaskDao.save(workFlowTask);
    }


    @Override
    public ResultBean taskListVueType(String type, Pageable pageable) {
        Assert.notNull(type, "type cannot be null");
        List<WorkFlowProcess> processList = processDao.findByBizTypeName(type);
        if (CollectionUtils.isEmpty(processList)) {
            return ResultBean.defaultSuccessResult();
        }
        pageable = PageDataUtils.addOrderByDesc(pageable, "id");
        Map<Long, String> codeMap = processList.stream().filter(r -> r.getCodePrefix() != null)
                .collect(Collectors.toMap(r -> r.getId(), r -> r.getCodePrefix()));
        Map<Long, String> bizMap = processList.stream().collect(Collectors.toMap(r -> r.getId(), r -> r.getBizName()));
        List<Long> processIdList = processList.stream().map(r -> r.getId()).collect(Collectors.toList());
        Page<WorkFlowTask> page = workFlowTaskDao.findByProcessIdInAndParentId(processIdList, 0L, pageable);
        for (WorkFlowTask task : page) {
            //setCodeDetail(codeMap.getOrDefault(task.getProcessId(), ""), task);
            task.setBizName(bizMap.getOrDefault(task.getProcessId(), ""));
        }
        return ResultBean.pageData(page.getContent(), page.getTotalElements());
    }

    /**
     * 获取分配信息
     *
     * @param taskName
     * @param objectIds
     * @param varMap
     * @param id
     * @param taskConfig
     * @return
     */
    private List<CountersignBean> getAssignMap(String taskName, String objectIds, Map<String, Object> varMap, Long id, WorkFlowTaskNameBean taskConfig) throws ApiBusinessException {
        List<CountersignBean> countersignList = Lists.newArrayList();
        countersignList.add(new CountersignBean(null, null, null));
        if (varMap == null || taskName == null) {
            return countersignList;
        }

        // 排他网关： 节点回退： 返回上个节点历史指定对象值
        if (varMap.get("param") != null && varMap.get("param").toString().equals("0")) {
            List<WorkFlowTaskAssignHistory> historyList = workFlowTaskAssignHistoryDao.findByTaskIdAndTaskName(id, taskName);
            if (!CollectionUtils.isEmpty(historyList)) {
                WorkFlowTaskAssignHistory history = historyList.get(0);
                CountersignBean countersignBean = countersignList.get(0);
                countersignBean.setAssignKey(history.getAssignKey());
                countersignBean.setAssignValue(history.getAssignValue());
                return countersignList;
            }
        }
        if (taskConfig != null) {
            Integer countersign = taskConfig.getCountersign();
            JSONObject fieldIds = JSONObject.parseObject(objectIds);
            countersignList = getCountersignBeans(countersignList, taskConfig, countersign, fieldIds);
        }
        return countersignList;
    }

    /**
     * 获取当前节点的执行信息
     *
     * @param workFlowId
     * @param taskName
     * @return
     */
    private WorkFlowTaskNameBean getCurTaskConfig(final Long workFlowId, final String taskName) {
        List<WorkFlowTaskNameBean> taskConfigList = workFlowProcessService.findTaskNameList(workFlowId);
        if (CollectionUtils.isNotEmpty(taskConfigList)) {
            Optional<WorkFlowTaskNameBean> optionalConfig = taskConfigList.stream().filter(item -> item.getTaskName().equals(taskName)).findFirst();
            if (optionalConfig.isPresent()) {
                return optionalConfig.get();
            }
        }
        return null;
    }

    /**
     * 保存任务分配历史记录通过会签类型
     *
     * @param taskName
     * @param taskId
     * @param operation
     * @param countersignList
     * @param countersign
     * @param nextTaskName
     */
    private void saveTaskAssignHistoryByCountersignType(String taskName, Long taskId, String operation, List<CountersignBean> countersignList, Integer countersign, String nextTaskName, String taskCode, String remark) {
        String assignKey = countersignList.get(0).getAssignKey();
        String assignValue = countersignList.get(0).getAssignValue();
        insertTaskAssignHistory(taskName, taskId, operation, nextTaskName, assignKey, assignValue, taskCode, remark);
        //  获取流程节点参与人配置信息
        /*if (CollectionUtils.isNotEmpty(countersignList)) {
            if (countersign == null || WorkFlowParticipantRuleEnum.ONE.getValue().equals(countersign)) {
                String assignKey = countersignList.get(0).getAssignKey();
                String assignValue = countersignList.get(0).getAssignValue();
                insertTaskAssignHistory(taskName, taskId, operation, nextTaskName, assignKey, assignValue, taskCode);
            } else if (WorkFlowParticipantRuleEnum.EVERYONE.getValue().equals(countersign) || WorkFlowParticipantRuleEnum.ONE_OF.getValue().equals(countersign)) {
                //TODO
                // 1. 2.1版本注释部分,2.2版本打开，后期优化为batch操作
                // 2. 2.1版本首先删除当前节点的所有日志，后续版本在流程打回时需要做对应日志记录
                for (CountersignBean bean : countersignList) {
                    insertTaskAssignHistory(taskName, taskId, operation, nextTaskName, bean.getAssignKey(), bean.getAssignValue(), taskCode);
                }
            }
        }*/
    }

    /**
     * insert 任务分配历史记录
     *
     * @param taskName
     * @param taskId
     * @param operation
     * @param nextTaskName
     * @param assignKey
     * @param assignValue
     */
    private void insertTaskAssignHistory(String taskName, Long taskId, String operation, String nextTaskName, String assignKey, String assignValue, String taskCode, String remark) {
        Long currentUser = Context.getCurrentUser().getRealUserId();
        WorkFlowTaskAssignHistory history = new WorkFlowTaskAssignHistory();
        history.setTaskId(taskId);
        history.setTaskName(taskName);
        history.setAssignKey(assignKey);
        history.setAssignValue(assignValue);
        history.setOperator(currentUser);
        history.setOperation(operation);
        history.setNextTaskName(nextTaskName);
        history.setTaskCode(taskCode);
        history.setRemark(remark);
        workFlowTaskAssignHistoryDao.save(history);
    }

    /**
     * 获取assign集合
     */
    private List<CountersignBean> getCountersignBeans(List<CountersignBean> countersignList, WorkFlowTaskNameBean taskNameBean,
                                                      Integer countersign, JSONObject fieldIds) throws ApiBusinessException {
        if (countersign == null || countersign == 0) {
            CountersignBean countersignBean = countersignList.get(0);
            countersignBean.setAssignKey(taskNameBean.getAssignKey());
            countersignBean.setAssignValue(taskNameBean.getAssignValue());
            if (WorkFlowAssignKey.FORM_OBJECT.getCode().equals(countersignBean.getAssignKey())) {
                countersignBean.setAssignKey(taskNameBean.getDiaType());
                final String assignValue = countersignBean.getAssignValue();
                //作业票电子围栏报警需要加入承包商作业人员，故修改ObjectId字段数据结构
                //会签/或签 存在多选情况
                if (JSONUtil.isJsonArray(assignValue)) {
                    JSONArray jsonArray = fieldIds.getJSONArray(assignValue);
                    JSONObject object = (JSONObject) jsonArray.get(0);
                    countersignBean.setAssignValue(object.getString("id"));
                } else {
                    Object ob = fieldIds.get(assignValue);
                    if (ob instanceof Integer) {
                        Object value = fieldIds.get(assignValue);
                        countersignBean.setAssignValue(value != null ? value.toString() : null);
                    }
                    if (ob instanceof JSONArray) {
                        //兼容旧数据
                        JSONArray jsonArray = fieldIds.getJSONArray(assignValue);
                        if (CollectionUtils.isEmpty(jsonArray)) {
                            countersignBean.setAssignKey(null);
                            countersignBean.setAssignValue(null);
                        } else {
                            Object value = jsonArray.get(0);
                            if (JSONUtil.isJsonObj(value.toString())) {
                                cn.hutool.json.JSONObject jsonObject = JSONUtil.parseObj(value);
                                Object idObj = jsonObject.get("id");
                                if (idObj != null) {
                                    countersignBean.setAssignValue(jsonObject.get("id").toString());
                                }
                            } else {
                                countersignBean.setAssignValue(value.toString());
                            }
                        }
                    }
                    //最老版本兼容的数据不再支持
                    //countersignBean.setAssignValue(fieldIds.getString(countersignBean.getAssignValue()));
                }
            }
            //如果组件下没有人，则所有人都可以执行任务
            hasUser(countersignBean);
        } else if (countersign == 1 || countersign == 2) {
            List<CountersignBean> tempList = taskNameBean.getCountersignList();
            if (!CollectionUtils.isEmpty(tempList)) {
                countersignList = tempList;
                List<CountersignBean> temp = Lists.newArrayList();
                for (CountersignBean bean : countersignList) {
                    if (WorkFlowAssignKey.FORM_OBJECT.getCode().equals(bean.getAssignKey())) {
                        try {
                            //会签/或签 存在多选情况
                            JSONArray jsonArray = fieldIds.getJSONArray(bean.getAssignValue());
                            for (Object o : jsonArray) {
                                JSONObject object = (JSONObject) o;
                                temp.add(new CountersignBean(bean.getDiaType(), object.getString("id"), null));
                            }
                        } catch (Exception e) {
                            //兼容旧数据
                            JSONArray jsonArray = fieldIds.getJSONArray(bean.getAssignValue());
                            if (jsonArray == null) {
                                temp.add(new CountersignBean(null, null, null));
                            } else {
                                for (Object o : jsonArray) {
                                    temp.add(new CountersignBean(bean.getDiaType(), o.toString(), null));
                                }
                            }

                            //最老版本兼容的数据不再支持
                            //temp.add(new CountersignBean(bean.getDiaType(), fieldIds.getString(bean.getAssignValue()), null));
                        }
                    } else {
                        temp.add(new CountersignBean(bean.getAssignKey(), bean.getAssignValue(), null));
                    }
                }
                //过滤assignValue为null
                countersignList = temp.stream().filter(r -> r.getAssignValue() != null).collect(Collectors.toList());
                //会签/或签 获取所有人员
                countersignList = setRealUser(countersignList);
            }
        }
        //去除key不为空，value为空的情况
        List<CountersignBean> list = countersignList.stream().filter(r -> {
            if (r.getAssignKey() != null) {
                return r.getAssignValue() != null;
            }
            return true;
        }).collect(Collectors.toList());
        if (org.springframework.util.CollectionUtils.isEmpty(list)) {
            list.add(new CountersignBean(null, null, null));
        }
        return list;
    }

    private void hasUser(CountersignBean bean) throws ApiBusinessException {
        String assignKey = bean.getAssignKey();
        String assignValue = bean.getAssignValue();
        if (StringUtils.isBlank(assignKey)) {
            return;
        }
        if (StringUtils.isBlank(assignValue)) {
            bean.setAssignKey(null);
            return;
        }
        WorkFlowAssignKey partnerType = WorkFlowAssignKey.findByCode(assignKey);
        if (partnerType != null) {
            switch (partnerType) {
                case DEPARTMENT:
                case JOB:
                case ROLE:
                case PERSON:
                    if (!StringUtils.isNumeric(assignValue)) {
                        String statusParam = WorkFlowAssignKey.findByCode(assignKey).getName();
                        throw new ApiBusinessException(Status.PROCESS_ASSIGNOR_NON_EXISTENT, statusParam);
                    }
                    break;
            }
        }
        List<Long> list = Lists.newArrayList();
        if ("department".equals(assignKey)) {
            list = baseUserDao.findIdByDepartId(Long.parseLong(assignValue));
        } else if ("job".equals(assignKey) || "post".equals(assignKey)) {
            list = baseUserDao.findIdByJob(Long.parseLong(assignValue));
        } else if ("role".equals(assignKey)) {
            list = baseRoleUserLoginRoleDao.findUserIdByRoleUserId(Long.parseLong(assignValue));
        } else if ("person".equals(assignKey)) {
            list.add(Long.parseLong(assignValue));
            //过滤已删除的人
            if (!CollectionUtils.isEmpty(list)) {
                list = list.stream().filter(userId -> baseUserDao.findOneById(userId) != null).collect(Collectors.toList());
            }
        }
        if (CollectionUtils.isEmpty(list)) {
            bean.setAssignKey(null);
            bean.setAssignValue(null);
        }
    }

    private List<CountersignBean> setRealUser(List<CountersignBean> countersignList) {
        //get all userId
        //department; job(post); person; role
        Map<String, List<CountersignBean>> map = countersignList.stream().collect(Collectors.groupingBy(CountersignBean::getAssignKey));
        List<CountersignBean> postList = map.getOrDefault("post", Lists.newArrayList());
        List<CountersignBean> jobList = map.getOrDefault("job", Lists.newArrayList());
        //job
        jobList.addAll(postList);
        List<Long> userIdList = Lists.newArrayList();
        if (!CollectionUtils.isEmpty(jobList)) {
            List<Long> jobIds = jobList.stream().map(r -> Long.parseLong(r.getAssignValue())).filter(Objects::nonNull).distinct().collect(Collectors.toList());
            List<Long> userIds = baseUserDao.findIdByJobIn(jobIds);
            userIdList.addAll(userIds);
        }
        //department
        List<CountersignBean> departmentList = map.get("department");
        if (!CollectionUtils.isEmpty(departmentList)) {
            List<Long> departIds = departmentList.stream().map(r -> Long.parseLong(r.getAssignValue())).filter(Objects::nonNull).distinct().collect(Collectors.toList());
            List<Long> userIds = baseUserDao.findIdByDepartIdIn(departIds);
            userIdList.addAll(userIds);
        }
        //person
        List<CountersignBean> personList = map.get("person");
        if (!CollectionUtils.isEmpty(personList)) {
            List<Long> userIds = personList.stream().map(r -> Long.parseLong(r.getAssignValue())).filter(Objects::nonNull).distinct().collect(Collectors.toList());
            //过滤已删除的人
            if (!CollectionUtils.isEmpty(userIds)) {
                userIds = userIds.stream().filter(userId -> baseUserDao.findOneById(userId) != null).collect(Collectors.toList());
            }
            userIdList.addAll(userIds);
        }
        //role
        List<CountersignBean> roleList = map.get("role");
        if (!CollectionUtils.isEmpty(roleList)) {
            List<Long> roleIds = roleList.stream().map(r -> Long.parseLong(r.getAssignValue())).filter(Objects::nonNull).distinct().collect(Collectors.toList());
            List<Long> userIds = baseRoleUserLoginRoleDao.findUserIdByRoleUserIds(roleIds);
            userIdList.addAll(userIds);
        }
        userIdList = userIdList.stream().filter(Objects::nonNull).distinct().collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(userIdList)) {
            List<CountersignBean> tempList = new ArrayList<>(userIdList.size());
            for (Long userId : userIdList) {
                tempList.add(new CountersignBean("person", userId.toString(), "person"));
            }
            return tempList;
        }
        //找不到人，生成一条任何人都可以做的任务
        else {
            countersignList = Lists.newArrayList();
            countersignList.add(new CountersignBean(null, null, null));
        }
        log.info("===========userIdList======" + JSON.toJSONString(userIdList));
        return countersignList;
    }


}
